[BUGFIX] DBAL: Fix retrieving the last insert id
[Packages/TYPO3.CMS.git] / typo3 / sysext / dbal / Classes / Database / DatabaseConnection.php
index ad837c0..4fb6db5 100644 (file)
@@ -1,79 +1,60 @@
 <?php
 namespace TYPO3\CMS\Dbal\Database;
 
-/***************************************************************
- *  Copyright notice
+/*
+ * This file is part of the TYPO3 CMS project.
  *
- *  (c) 2004-2013 Kasper Skårhøj (kasperYYYY@typo3.com)
- *  (c) 2004-2013 Karsten Dambekalns <karsten@typo3.org>
- *  (c) 2009-2013 Xavier Perseguers <xavier@typo3.org>
- *  All rights reserved
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
  *
- *  This script is part of the TYPO3 project. The TYPO3 project is
- *  free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
  *
- *  The GNU General Public License can be found at
- *  http://www.gnu.org/copyleft/gpl.html.
- *  A copy is found in the textfile GPL.txt and important notices to the license
- *  from the author is found in LICENSE.txt distributed with these scripts.
- *
- *
- *  This script is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  This copyright notice MUST APPEAR in all copies of the script!
- ***************************************************************/
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Core\Utility\GeneralUtility;
 
 /**
  * TYPO3 database abstraction layer
- *
- * @author     Kasper Skårhøj <kasper@typo3.com>
- * @author     Karsten Dambekalns <k.dambekalns@fishfarm.de>
- * @author     Xavier Perseguers <xavier@typo3.org>
  */
 class DatabaseConnection extends \TYPO3\CMS\Core\Database\DatabaseConnection {
 
-       // Internal, static:
        /**
-        * @todo Define visibility
+        * @var bool
         */
-       public $printErrors = FALSE;
+       protected $printErrors = FALSE;
 
-       // Enable output of SQL errors after query executions. Set through TYPO3_CONF_VARS, see init()
        /**
-        * @todo Define visibility
+        * Enable output of SQL errors after query executions.
+        * @var bool
         */
        public $debug = FALSE;
 
-       // Enable debug mode. Set through TYPO3_CONF_VARS, see init()
        /**
-        * @todo Define visibility
+        * Enable debug mode
+        * @var bool
         */
        public $conf = array();
 
-       // Configuration array, copied from TYPO3_CONF_VARS in constructor.
        /**
-        * @todo Define visibility
+        * Configuration array, copied from TYPO3_CONF_VARS in constructor.
+        * @var array
         */
        public $mapping = array();
 
-       // See manual.
        /**
-        * @todo Define visibility
+        * See manual
+        * @var array
         */
-       public $table2handlerKeys = array();
+       protected $table2handlerKeys = array();
 
-       // See manual.
        /**
-        * @todo Define visibility
+        * See manual
+        * @var array
         */
        public $handlerCfg = array(
-               // See manual.
                '_DEFAULT' => array(
                        'type' => 'native',
                        'config' => array(
@@ -96,85 +77,80 @@ class DatabaseConnection extends \TYPO3\CMS\Core\Database\DatabaseConnection {
                )
        );
 
-       // Internal, dynamic:
        /**
-        * @todo Define visibility
+        * Contains instance of the handler objects as they are created.
+        *
+        * Exception is the native mySQL calls, which are registered as an array with keys
+        * "handlerType" = "native" and
+        * "link" pointing to the link object of the connection.
+        *
+        * @var array
         */
        public $handlerInstance = array();
 
-       // Contains instance of the handler objects as they are created. Exception is the native mySQL calls which are registered as an array with keys "handlerType" = "native" and "link" pointing to the link resource for the connection.
        /**
-        * @todo Define visibility
+        * Storage of the handler key of last ( SELECT) query - used for subsequent fetch-row calls etc.
+        * @var string
         */
        public $lastHandlerKey = '';
 
-       // Storage of the handler key of last ( SELECT) query - used for subsequent fetch-row calls etc.
        /**
-        * @todo Define visibility
+        * Storage of last SELECT query
+        * @var string
         */
-       public $lastQuery = '';
+       protected $lastQuery = '';
 
-       // Storage of last SELECT query
        /**
-        * @todo Define visibility
+        * The last parsed query array
+        * @var array
         */
-       public $lastParsedAndMappedQueryArray = array();
+       protected $lastParsedAndMappedQueryArray = array();
 
-       // Query array, the last one parsed
        /**
-        * @todo Define visibility
+        * @var array
         */
-       public $resourceIdToTableNameMap = array();
+       protected $resourceIdToTableNameMap = array();
 
-       // Mapping of resource ids to table names.
-       // Internal, caching:
        /**
-        * @todo Define visibility
+        * @var array
         */
-       public $cache_handlerKeyFromTableList = array();
+       protected $cache_handlerKeyFromTableList = array();
 
-       // Caching handlerKeys for table lists
        /**
-        * @todo Define visibility
+        * @var array
         */
-       public $cache_mappingFromTableList = array();
+       protected $cache_mappingFromTableList = array();
 
-       // Caching mapping information for table lists
        /**
-        * @todo Define visibility
+        * parsed SQL from standard DB dump file
+        * @var array
         */
        public $cache_autoIncFields = array();
 
-       // parsed SQL from standard DB dump file
        /**
-        * @todo Define visibility
+        * @var array
         */
        public $cache_fieldType = array();
 
-       // field types for tables/fields
        /**
-        * @todo Define visibility
+        * @var array
         */
        public $cache_primaryKeys = array();
 
-       // primary keys
        /**
-        * The cache identifier for the field information cache
-        *
         * @var string
         */
-       protected $cacheIdentifier = 't3lib_db_fieldInfo';
+       protected $cacheIdentifier = 'DatabaseConnection_fieldInfo';
 
        /**
         * SQL parser
         *
-        * @var \TYPO3\CMS\Core\Database\SqlParser
-        * @todo Define visibility
+        * @var \TYPO3\CMS\Dbal\Database\SqlParser
         */
        public $SQLparser;
 
        /**
-        * @var \TYPO3\CMS\Install\Sql\SchemaMigrator
+        * @var \TYPO3\CMS\Install\Service\SqlSchemaMigrationService
         */
        protected $installerSql = NULL;
 
@@ -186,25 +162,66 @@ class DatabaseConnection extends \TYPO3\CMS\Core\Database\DatabaseConnection {
        protected $queryCache;
 
        /**
+        * mysql_field_type compatibility map
+        * taken from: http://www.php.net/manual/en/mysqli-result.fetch-field-direct.php#89117
+        * Constant numbers see http://php.net/manual/en/mysqli.constants.php
+        *
+        * @var array
+        */
+       protected $mysqlDataTypeMapping = array(
+               MYSQLI_TYPE_TINY => 'tinyint',
+               MYSQLI_TYPE_CHAR => 'tinyint',
+               MYSQLI_TYPE_SHORT => 'smallint',
+               MYSQLI_TYPE_LONG => 'int',
+               MYSQLI_TYPE_FLOAT => 'float',
+               MYSQLI_TYPE_DOUBLE => 'double',
+               MYSQLI_TYPE_TIMESTAMP => 'timestamp',
+               MYSQLI_TYPE_LONGLONG => 'bigint',
+               MYSQLI_TYPE_INT24 => 'mediumint',
+               MYSQLI_TYPE_DATE => 'date',
+               MYSQLI_TYPE_NEWDATE => 'date',
+               MYSQLI_TYPE_TIME => 'time',
+               MYSQLI_TYPE_DATETIME => 'datetime',
+               MYSQLI_TYPE_YEAR => 'year',
+               MYSQLI_TYPE_BIT => 'bit',
+               MYSQLI_TYPE_INTERVAL => 'interval',
+               MYSQLI_TYPE_ENUM => 'enum',
+               MYSQLI_TYPE_SET => 'set',
+               MYSQLI_TYPE_TINY_BLOB => 'blob',
+               MYSQLI_TYPE_MEDIUM_BLOB => 'blob',
+               MYSQLI_TYPE_LONG_BLOB => 'blob',
+               MYSQLI_TYPE_BLOB => 'blob',
+               MYSQLI_TYPE_VAR_STRING => 'varchar',
+               MYSQLI_TYPE_STRING => 'char',
+               MYSQLI_TYPE_DECIMAL => 'decimal',
+               MYSQLI_TYPE_NEWDECIMAL => 'decimal',
+               MYSQLI_TYPE_GEOMETRY => 'geometry'
+       );
+
+       /**
+        * @var Specifics\AbstractSpecifics
+        */
+       protected $dbmsSpecifics;
+
+       /**
         * Constructor.
         * Creates SQL parser object and imports configuration from $TYPO3_CONF_VARS['EXTCONF']['dbal']
         */
        public function __construct() {
                // Set SQL parser object for internal use:
-               $this->SQLparser = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Database\\SqlParser');
-               $this->installerSql = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Install\\Sql\\SchemaMigrator');
-               $this->queryCache = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Cache\\CacheManager')->getCache('dbal');
+               $this->SQLparser = GeneralUtility::makeInstance(\TYPO3\CMS\Dbal\Database\SqlParser::class, $this);
+               $this->installerSql = GeneralUtility::makeInstance(\TYPO3\CMS\Install\Service\SqlSchemaMigrationService::class);
+               $this->queryCache = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Cache\CacheManager::class)->getCache('dbal');
                // Set internal variables with configuration:
                $this->conf = $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['dbal'];
-               $this->initInternalVariables();
        }
 
        /**
-        * Setting internal variables from $this->conf.
+        * Initialize the database connection
         *
-        * @return      void
+        * @return void
         */
-       protected function initInternalVariables() {
+       public function initialize() {
                // Set outside configuration:
                if (isset($this->conf['mapping'])) {
                        $this->mapping = $this->conf['mapping'];
@@ -212,13 +229,44 @@ class DatabaseConnection extends \TYPO3\CMS\Core\Database\DatabaseConnection {
                if (isset($this->conf['table2handlerKeys'])) {
                        $this->table2handlerKeys = $this->conf['table2handlerKeys'];
                }
+
+               $specificsClassName = Specifics\NullSpecifics::class;
                if (isset($this->conf['handlerCfg'])) {
                        $this->handlerCfg = $this->conf['handlerCfg'];
+
+                       if (isset($this->handlerCfg['_DEFAULT']['config']['driver'])) {
+                               // load DBMS specifics
+                               $driver = $this->handlerCfg['_DEFAULT']['config']['driver'];
+                               $className = 'TYPO3\\CMS\\Dbal\\Database\\Specifics\\' . ucfirst(strtolower($driver)) . 'Specifics';
+                               if (class_exists($className)) {
+                                       if (!is_subclass_of($className, Specifics\AbstractSpecifics::class)) {
+                                               throw new \InvalidArgumentException($className . ' must inherit from ' . Specifics\AbstractSpecifics::class, 1416919866);
+                                       }
+                                       $specificsClassName = $className;
+                               }
+                       }
                }
+               $this->dbmsSpecifics = GeneralUtility::makeInstance($specificsClassName);
                $this->cacheFieldInfo();
                // Debugging settings:
-               $this->printErrors = $this->conf['debugOptions']['printErrors'] ? TRUE : FALSE;
-               $this->debug = $this->conf['debugOptions']['enabled'] ? TRUE : FALSE;
+               $this->printErrors = !empty($this->conf['debugOptions']['printErrors']);
+               $this->debug = !empty($this->conf['debugOptions']['enabled']);
+       }
+
+       /**
+        * Gets the DBMS specifics object
+        *
+        * @return Specifics\AbstractSpecifics
+        */
+       public function getSpecifics() {
+               return $this->dbmsSpecifics;
+       }
+
+       /**
+        * @return \TYPO3\CMS\Core\Cache\Frontend\PhpFrontend
+        */
+       protected function getFieldInfoCache() {
+               return GeneralUtility::makeInstance(\TYPO3\CMS\Core\Cache\CacheManager::class)->getCache('cache_phpcode');
        }
 
        /**
@@ -227,8 +275,7 @@ class DatabaseConnection extends \TYPO3\CMS\Core\Database\DatabaseConnection {
         * @return void
         */
        public function clearCachedFieldInfo() {
-               $phpCodeCache = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Cache\\CacheManager')->getCache('cache_phpcode');
-               $phpCodeCache->flushByTag('t3lib_db');
+               $this->getFieldInfoCache()->flushByTag('DatabaseConnection');
        }
 
        /**
@@ -237,7 +284,7 @@ class DatabaseConnection extends \TYPO3\CMS\Core\Database\DatabaseConnection {
         * @return void
         */
        public function cacheFieldInfo() {
-               $phpCodeCache = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Cache\\CacheManager')->getCache('cache_phpcode');
+               $phpCodeCache = $this->getFieldInfoCache();
                // try to fetch cache
                // cache is flushed when admin_query() is called
                if ($phpCodeCache->has($this->cacheIdentifier)) {
@@ -249,7 +296,7 @@ class DatabaseConnection extends \TYPO3\CMS\Core\Database\DatabaseConnection {
                        $this->analyzeCachingTables();
                        $this->analyzeExtensionTables();
                        $completeFieldInformation = $this->getCompleteFieldInformation();
-                       $phpCodeCache->set($this->cacheIdentifier, $this->getCacheableString($completeFieldInformation), array('t3lib_db'));
+                       $phpCodeCache->set($this->cacheIdentifier, $this->getCacheableString($completeFieldInformation), array('DatabaseConnection'));
                }
        }
 
@@ -261,7 +308,8 @@ class DatabaseConnection extends \TYPO3\CMS\Core\Database\DatabaseConnection {
         * @return void
         */
        protected function analyzeCachingTables() {
-               $this->parseAndAnalyzeSql(\TYPO3\CMS\Core\Cache\Cache::getDatabaseTableDefinitions());
+               $schemaService = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Cache\DatabaseSchemaService::class);
+               $this->parseAndAnalyzeSql($schemaService->getCachingFrameworkRequiredDatabaseSchema());
        }
 
        /**
@@ -271,12 +319,15 @@ class DatabaseConnection extends \TYPO3\CMS\Core\Database\DatabaseConnection {
         * @return void
         */
        protected function analyzeExtensionTables() {
-               foreach ($GLOBALS['TYPO3_LOADED_EXT'] as $extensionConfiguration) {
-                       if (!is_array($extensionConfiguration) || !isset($extensionConfiguration['ext_tables.sql'])) {
-                               continue;
+               if (isset($GLOBALS['TYPO3_LOADED_EXT']) && (is_array($GLOBALS['TYPO3_LOADED_EXT']) || $GLOBALS['TYPO3_LOADED_EXT'] instanceof \ArrayAccess)) {
+                       foreach ($GLOBALS['TYPO3_LOADED_EXT'] as $extensionConfiguration) {
+                               $isArray = (is_array($extensionConfiguration) || $extensionConfiguration instanceof \ArrayAccess);
+                               if (!$isArray || ($isArray && !isset($extensionConfiguration['ext_tables.sql']))) {
+                                       continue;
+                               }
+                               $extensionsSql = file_get_contents($extensionConfiguration['ext_tables.sql']);
+                               $this->parseAndAnalyzeSql($extensionsSql);
                        }
-                       $extensionsSql = file_get_contents($extensionConfiguration['ext_tables.sql']);
-                       $this->parseAndAnalyzeSql($extensionsSql);
                }
        }
 
@@ -318,16 +369,21 @@ class DatabaseConnection extends \TYPO3\CMS\Core\Database\DatabaseConnection {
        /**
         * Analyzes fields and adds the extracted information to the field type, auto increment and primary key info caches.
         *
-        * @param array $parsedExtSQL The output produced by \TYPO3\CMS\Install\Sql\SchemaMigrator->getFieldDefinitions_fileContent()
+        * @param array $parsedExtSQL The output produced by \TYPO3\CMS\Install\Service\SqlSchemaMigrationService->getFieldDefinitions_fileContent()
         * @return void
         */
        protected function analyzeFields($parsedExtSQL) {
                foreach ($parsedExtSQL as $table => $tdef) {
+                       // check if table is mapped
+                       if (isset($this->mapping[$table])) {
+                               $table = $this->mapping[$table]['mapTableName'];
+                       }
                        if (is_array($tdef['fields'])) {
-                               foreach ($tdef['fields'] as $field => $fdef) {
-                                       $fdef = $this->SQLparser->parseFieldDef($fdef);
-                                       $this->cache_fieldType[$table][$field]['type'] = $fdef['fieldType'];
-                                       $this->cache_fieldType[$table][$field]['metaType'] = $this->MySQLMetaType($fdef['fieldType']);
+                               foreach ($tdef['fields'] as $field => $fdefString) {
+                                       $fdef = $this->SQLparser->parseFieldDef($fdefString);
+                                       $fieldType = isset($fdef['fieldType']) ? $fdef['fieldType'] : '';
+                                       $this->cache_fieldType[$table][$field]['type'] = $fieldType;
+                                       $this->cache_fieldType[$table][$field]['metaType'] = $this->dbmsSpecifics->getMetaFieldType($fieldType);
                                        $this->cache_fieldType[$table][$field]['notnull'] = isset($fdef['featureIndex']['NOTNULL']) && !$this->SQLparser->checkEmptyDefaultValue($fdef['featureIndex']) ? 1 : 0;
                                        if (isset($fdef['featureIndex']['DEFAULT'])) {
                                                $default = $fdef['featureIndex']['DEFAULT']['value'][0];
@@ -350,9 +406,12 @@ class DatabaseConnection extends \TYPO3\CMS\Core\Database\DatabaseConnection {
        /**
         * This function builds all definitions for mapped tables and fields
         *
+        * @param array $fieldInfo
+        * @return array
+        *
         * @see cacheFieldInfo()
         */
-       protected function mapCachedFieldInfo($fieldInfo) {
+       protected function mapCachedFieldInfo(array $fieldInfo) {
                if (is_array($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['dbal']['mapping'])) {
                        foreach ($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['dbal']['mapping'] as $mappedTable => $mappedConf) {
                                if (array_key_exists($mappedTable, $fieldInfo['incFields'])) {
@@ -364,6 +423,7 @@ class DatabaseConnection extends \TYPO3\CMS\Core\Database\DatabaseConnection {
                                        }
                                }
                                if (array_key_exists($mappedTable, $fieldInfo['fieldTypes'])) {
+                                       $tempMappedFieldConf = array();
                                        foreach ($fieldInfo['fieldTypes'][$mappedTable] as $field => $fieldConf) {
                                                $tempMappedFieldConf[$mappedConf['mapFieldNames'][$field]] = $fieldConf;
                                        }
@@ -388,24 +448,29 @@ class DatabaseConnection extends \TYPO3\CMS\Core\Database\DatabaseConnection {
         * These functions are extending counterparts in the parent class.
         *
         **************************************/
-       /* From the ADOdb documentation, this is what we do (_Execute for SELECT, _query for the other actions)Execute() is the default way to run queries. You can use the low-level functions _Execute() and _query() to reduce query overhead.
-       Both these functions share the same parameters as Execute().If you do not have any bind parameters or your database supports binding (without emulation), then you can call _Execute() directly.
-       Calling this function bypasses bind emulation. Debugging is still supported in _Execute().If you do not require debugging facilities nor emulated binding, and do not require a recordset to be returned, then you can call _query.
-       This is great for inserts, updates and deletes. Calling this function bypasses emulated binding, debugging, and recordset handling. Either
-       the resultid, TRUE or FALSE are returned by _query().
+       /*
+        * From the ADOdb documentation, this is what we do (_Execute for SELECT, _query for the other actions)Execute()
+        * is the default way to run queries. You can use the low-level functions _Execute() and _query() to reduce query overhead.
+        * Both these functions share the same parameters as Execute().If you do not have any bind parameters or your database
+        * supports binding (without emulation), then you can call _Execute() directly.
+        * Calling this function bypasses bind emulation. Debugging is still supported in _Execute().If you do not require
+        * debugging facilities nor emulated binding, and do not require a recordset to be returned, then you can call _query.
+        * This is great for inserts, updates and deletes. Calling this function bypasses emulated binding, debugging,
+        * and recordset handling. Either the resultid, TRUE or FALSE are returned by _query().
         */
+
        /**
-        * Inserts a record for $table from the array with field/value pairs $fields_values.
+        * Creates and executes an INSERT SQL-statement for $table from the array with field/value pairs $fields_values.
+        * Using this function specifically allows us to handle BLOB and CLOB fields depending on DB
         *
-        * @param       string          Table name
-        * @param       array           Field values as key=>value pairs. Values will be escaped internally. Typically you would fill an array like "$insertFields" with 'fieldname'=>'value' and pass it to this function as argument.
-        * @param mixed List/array of keys NOT to quote (eg. SQL functions)
-        * @return      mixed           Result from handler, usually TRUE when success and FALSE on failure
+        * @param string $table Table name
+        * @param array $fields_values Field values as key=>value pairs. Values will be escaped internally. Typically you would fill an array like "$insertFields" with 'fieldname'=>'value' and pass it to this function as argument.
+        * @param bool|array|string $no_quote_fields See fullQuoteArray()
+        * @return bool|\mysqli_result|object MySQLi result object / DBAL object
+        * @throws \RuntimeException
         */
-       public function exec_INSERTquery($table, $fields_values, $no_quote_fields = '') {
-               if ($this->debug) {
-                       $pt = \TYPO3\CMS\Core\Utility\GeneralUtility::milliseconds();
-               }
+       public function exec_INSERTquery($table, $fields_values, $no_quote_fields = FALSE) {
+               $pt = $this->debug ? GeneralUtility::milliseconds() : 0;
                // Do field mapping if needed:
                $ORIG_tableName = $table;
                if ($tableArray = $this->map_needMapping($table)) {
@@ -418,109 +483,124 @@ class DatabaseConnection extends \TYPO3\CMS\Core\Database\DatabaseConnection {
                }
                // Select API:
                $this->lastHandlerKey = $this->handler_getFromTableList($table);
-               $hType = (string) $this->handlerCfg[$this->lastHandlerKey]['type'];
+               $hType = (string)$this->handlerCfg[$this->lastHandlerKey]['type'];
+               $sqlResult = NULL;
                switch ($hType) {
-               case 'native':
-                       if ($this->lastHandlerKey === '_DEFAULT' && !$this->isConnected()) {
-                               $this->connectDB();
-                       }
-                       $this->lastQuery = $this->INSERTquery($table, $fields_values, $no_quote_fields);
-                       if (is_string($this->lastQuery)) {
-                               $sqlResult = mysql_query($this->lastQuery, $this->handlerInstance[$this->lastHandlerKey]['link']);
-                       } else {
-                               $sqlResult = mysql_query($this->lastQuery[0], $this->handlerInstance[$this->lastHandlerKey]['link']);
-                               $new_id = $this->sql_insert_id();
-                               $where = $this->cache_autoIncFields[$table] . '=' . $new_id;
-                               foreach ($this->lastQuery[1] as $field => $content) {
-                                       mysql_query('UPDATE ' . $this->quoteFromTables($table) . ' SET ' . $this->quoteFromTables($field) . '=' . $this->fullQuoteStr($content, $table) . ' WHERE ' . $this->quoteWhereClause($where), $this->handlerInstance[$this->lastHandlerKey]['link']);
-                               }
-                       }
-                       break;
-               case 'adodb':
-                       // auto generate ID for auto_increment fields if not present (static import needs this!)
-                       // should we check the table name here (static_*)?
-                       if (isset($this->cache_autoIncFields[$table])) {
-                               if (isset($fields_values[$this->cache_autoIncFields[$table]])) {
-                                       $new_id = $fields_values[$this->cache_autoIncFields[$table]];
-                                       if ($table != 'tx_dbal_debuglog') {
-                                               $this->handlerInstance[$this->lastHandlerKey]->last_insert_id = $new_id;
-                                       }
+                       case 'native':
+                               $this->lastQuery = $this->INSERTquery($table, $fields_values, $no_quote_fields);
+                               if (is_string($this->lastQuery)) {
+                                       $sqlResult = $this->query($this->lastQuery);
                                } else {
-                                       $new_id = $this->handlerInstance[$this->lastHandlerKey]->GenID($table . '_' . $this->cache_autoIncFields[$table], $this->handlerInstance[$this->lastHandlerKey]->sequenceStart);
-                                       $fields_values[$this->cache_autoIncFields[$table]] = $new_id;
-                                       if ($table != 'tx_dbal_debuglog') {
-                                               $this->handlerInstance[$this->lastHandlerKey]->last_insert_id = $new_id;
+                                       $sqlResult = $this->query($this->lastQuery[0]);
+                                       $new_id = $this->sql_insert_id();
+                                       $where = $this->cache_autoIncFields[$table] . '=' . $new_id;
+                                       foreach ($this->lastQuery[1] as $field => $content) {
+                                               $stmt = 'UPDATE ' . $this->quoteFromTables($table) . ' SET ' . $this->quoteFromTables($field) . '=' . $this->fullQuoteStr($content, $table, TRUE) . ' WHERE ' . $this->quoteWhereClause($where);
+                                               $this->query($stmt);
                                        }
                                }
-                       }
-                       $this->lastQuery = $this->INSERTquery($table, $fields_values, $no_quote_fields);
-                       if (is_string($this->lastQuery)) {
-                               $sqlResult = $this->handlerInstance[$this->lastHandlerKey]->_query($this->lastQuery, FALSE);
-                       } else {
-                               $this->handlerInstance[$this->lastHandlerKey]->StartTrans();
-                               if (strlen($this->lastQuery[0])) {
-                                       $sqlResult = $this->handlerInstance[$this->lastHandlerKey]->_query($this->lastQuery[0], FALSE);
+                               break;
+                       case 'adodb':
+                               // auto generate ID for auto_increment fields if not present (static import needs this!)
+                               // should we check the table name here (static_*)?
+                               if (isset($this->cache_autoIncFields[$table])) {
+                                       if (isset($fields_values[$this->cache_autoIncFields[$table]])) {
+                                               $new_id = $fields_values[$this->cache_autoIncFields[$table]];
+                                               if ($table != 'tx_dbal_debuglog') {
+                                                       $this->handlerInstance[$this->lastHandlerKey]->last_insert_id = $new_id;
+                                               }
+                                       } elseif (!$this->handlerInstance[$this->lastHandlerKey]->hasInsertID) {
+                                               // The table does not support auto-incremented fields, fall back to
+                                               // using a sequence table to simulate the auto-increment
+                                               $new_id = $this->handlerInstance[$this->lastHandlerKey]->GenID($table . '_' . $this->cache_autoIncFields[$table], $this->handlerInstance[$this->lastHandlerKey]->sequenceStart);
+                                               $fields_values[$this->cache_autoIncFields[$table]] = $new_id;
+                                               if ($table != 'tx_dbal_debuglog') {
+                                                       $this->handlerInstance[$this->lastHandlerKey]->last_insert_id = $new_id;
+                                               }
+                                       }
                                }
-                               if (is_array($this->lastQuery[1])) {
-                                       foreach ($this->lastQuery[1] as $field => $content) {
-                                               if (empty($content)) {
-                                                       continue;
+                               $this->lastQuery = $this->INSERTquery($table, $fields_values, $no_quote_fields);
+                               if (is_string($this->lastQuery)) {
+                                       $sqlResult = $this->handlerInstance[$this->lastHandlerKey]->_query($this->lastQuery, FALSE);
+                                       if ($this->handlerInstance[$this->lastHandlerKey]->hasInsertID && !empty($this->cache_autoIncFields[$table])) {
+                                               // The table is able to retrieve the ID of the last insert, use it to update the blob below
+                                               $new_id = $this->handlerInstance[$this->lastHandlerKey]->Insert_ID($table, $this->cache_autoIncFields[$table]);
+                                               if ($table !== 'tx_dbal_debuglog') {
+                                                       $this->handlerInstance[$this->lastHandlerKey]->last_insert_id = $new_id;
                                                }
-                                               if (isset($this->cache_autoIncFields[$table]) && isset($new_id)) {
-                                                       $this->handlerInstance[$this->lastHandlerKey]->UpdateBlob($this->quoteFromTables($table), $field, $content, $this->quoteWhereClause($this->cache_autoIncFields[$table] . '=' . $new_id));
-                                               } elseif (isset($this->cache_primaryKeys[$table])) {
-                                                       $where = '';
-                                                       $pks = explode(',', $this->cache_primaryKeys[$table]);
-                                                       foreach ($pks as $pk) {
-                                                               if (isset($fields_values[$pk])) {
-                                                                       $where .= $pk . '=' . $this->fullQuoteStr($fields_values[$pk], $table) . ' AND ';
-                                                               }
+                                       }
+                               } else {
+                                       $this->handlerInstance[$this->lastHandlerKey]->StartTrans();
+                                       if ((string)$this->lastQuery[0] !== '') {
+                                               $sqlResult = $this->handlerInstance[$this->lastHandlerKey]->_query($this->lastQuery[0], FALSE);
+                                               if ($this->handlerInstance[$this->lastHandlerKey]->hasInsertID && !empty($this->cache_autoIncFields[$table])) {
+                                                       // The table is able to retrieve the ID of the last insert, use it to update the blob below
+                                                       $new_id = $this->handlerInstance[$this->lastHandlerKey]->Insert_ID($table, $this->cache_autoIncFields[$table]);
+                                                       if ($table !== 'tx_dbal_debuglog') {
+                                                               $this->handlerInstance[$this->lastHandlerKey]->last_insert_id = $new_id;
                                                        }
-                                                       $where = $this->quoteWhereClause($where . '1=1');
-                                                       $this->handlerInstance[$this->lastHandlerKey]->UpdateBlob($this->quoteFromTables($table), $field, $content, $where);
-                                               } else {
-                                                       $this->handlerInstance[$this->lastHandlerKey]->CompleteTrans(FALSE);
-                                                       // Should never ever happen
-                                                       throw new \RuntimeException('Could not update BLOB >>>> no WHERE clause found!', 1321860519);
                                                }
                                        }
-                               }
-                               if (is_array($this->lastQuery[2])) {
-                                       foreach ($this->lastQuery[2] as $field => $content) {
-                                               if (empty($content)) {
-                                                       continue;
+                                       if (is_array($this->lastQuery[1])) {
+                                               foreach ($this->lastQuery[1] as $field => $content) {
+                                                       if (empty($content)) {
+                                                               continue;
+                                                       }
+                                                       if (isset($this->cache_autoIncFields[$table]) && isset($new_id)) {
+                                                               $this->handlerInstance[$this->lastHandlerKey]->UpdateBlob($this->quoteFromTables($table), $field, $content, $this->quoteWhereClause($this->cache_autoIncFields[$table] . '=' . $new_id));
+                                                       } elseif (isset($this->cache_primaryKeys[$table])) {
+                                                               $where = '';
+                                                               $pks = explode(',', $this->cache_primaryKeys[$table]);
+                                                               foreach ($pks as $pk) {
+                                                                       if (isset($fields_values[$pk])) {
+                                                                               $where .= $pk . '=' . $this->fullQuoteStr($fields_values[$pk], $table) . ' AND ';
+                                                                       }
+                                                               }
+                                                               $where = $this->quoteWhereClause($where . '1=1');
+                                                               $this->handlerInstance[$this->lastHandlerKey]->UpdateBlob($this->quoteFromTables($table), $field, $content, $where);
+                                                       } else {
+                                                               $this->handlerInstance[$this->lastHandlerKey]->CompleteTrans(FALSE);
+                                                               // Should never ever happen
+                                                               throw new \RuntimeException('Could not update BLOB >>>> no WHERE clause found!', 1321860519);
+                                                       }
                                                }
-                                               if (isset($this->cache_autoIncFields[$table]) && isset($new_id)) {
-                                                       $this->handlerInstance[$this->lastHandlerKey]->UpdateClob($this->quoteFromTables($table), $field, $content, $this->quoteWhereClause($this->cache_autoIncFields[$table] . '=' . $new_id));
-                                               } elseif (isset($this->cache_primaryKeys[$table])) {
-                                                       $where = '';
-                                                       $pks = explode(',', $this->cache_primaryKeys[$table]);
-                                                       foreach ($pks as $pk) {
-                                                               if (isset($fields_values[$pk])) {
-                                                                       $where .= $pk . '=' . $this->fullQuoteStr($fields_values[$pk], $table) . ' AND ';
+                                       }
+                                       if (is_array($this->lastQuery[2])) {
+                                               foreach ($this->lastQuery[2] as $field => $content) {
+                                                       if (empty($content)) {
+                                                               continue;
+                                                       }
+                                                       if (isset($this->cache_autoIncFields[$table]) && isset($new_id)) {
+                                                               $this->handlerInstance[$this->lastHandlerKey]->UpdateClob($this->quoteFromTables($table), $field, $content, $this->quoteWhereClause($this->cache_autoIncFields[$table] . '=' . $new_id));
+                                                       } elseif (isset($this->cache_primaryKeys[$table])) {
+                                                               $where = '';
+                                                               $pks = explode(',', $this->cache_primaryKeys[$table]);
+                                                               foreach ($pks as $pk) {
+                                                                       if (isset($fields_values[$pk])) {
+                                                                               $where .= $pk . '=' . $this->fullQuoteStr($fields_values[$pk], $table) . ' AND ';
+                                                                       }
                                                                }
+                                                               $where = $this->quoteWhereClause($where . '1=1');
+                                                               $this->handlerInstance[$this->lastHandlerKey]->UpdateClob($this->quoteFromTables($table), $field, $content, $where);
+                                                       } else {
+                                                               $this->handlerInstance[$this->lastHandlerKey]->CompleteTrans(FALSE);
+                                                               // Should never ever happen
+                                                               throw new \RuntimeException('Could not update CLOB >>>> no WHERE clause found!', 1310027337);
                                                        }
-                                                       $where = $this->quoteWhereClause($where . '1=1');
-                                                       $this->handlerInstance[$this->lastHandlerKey]->UpdateClob($this->quoteFromTables($table), $field, $content, $where);
-                                               } else {
-                                                       $this->handlerInstance[$this->lastHandlerKey]->CompleteTrans(FALSE);
-                                                       // Should never ever happen
-                                                       throw new \RuntimeException('Could not update CLOB >>>> no WHERE clause found!', 1310027337);
                                                }
                                        }
+                                       $this->handlerInstance[$this->lastHandlerKey]->CompleteTrans();
                                }
-                               $this->handlerInstance[$this->lastHandlerKey]->CompleteTrans();
-                       }
-                       break;
-               case 'userdefined':
-                       $sqlResult = $this->handlerInstance[$this->lastHandlerKey]->exec_INSERTquery($table, $fields_values, $no_quote_fields);
-                       break;
+                               break;
+                       case 'userdefined':
+                               $sqlResult = $this->handlerInstance[$this->lastHandlerKey]->exec_INSERTquery($table, $fields_values, $no_quote_fields);
+                               break;
                }
                if ($this->printErrors && $this->sql_error()) {
                        debug(array($this->lastQuery, $this->sql_error()));
                }
                if ($this->debug) {
-                       $this->debugHandler('exec_INSERTquery', \TYPO3\CMS\Core\Utility\GeneralUtility::milliseconds() - $pt, array(
+                       $this->debugHandler('exec_INSERTquery', GeneralUtility::milliseconds() - $pt, array(
                                'handlerType' => $hType,
                                'args' => array($table, $fields_values),
                                'ORIG_tablename' => $ORIG_tableName
@@ -535,31 +615,26 @@ class DatabaseConnection extends \TYPO3\CMS\Core\Database\DatabaseConnection {
 
        /**
         * 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
+        * @param string $table Table name
+        * @param array $fields Field names
+        * @param array $rows Table rows. Each row should be an array with field values mapping to $fields
+        * @param bool|array|string $no_quote_fields See fullQuoteArray()
+        * @return bool|\mysqli_result|object MySQLi result object / DBAL object
         */
        public function exec_INSERTmultipleRows($table, array $fields, array $rows, $no_quote_fields = FALSE) {
-               if ((string) $this->handlerCfg[$this->lastHandlerKey]['type'] === 'native') {
+               $res = NULL;
+               if ((string)$this->handlerCfg[$this->lastHandlerKey]['type'] === 'native') {
                        $this->lastHandlerKey = $this->handler_getFromTableList($table);
-                       if ($this->lastHandlerKey === '_DEFAULT' && !$this->isConnected()) {
-                               $this->connectDB();
-                       }
-                       mysql_query(
-                               parent::INSERTmultipleRows($table, $fields, $rows, $no_quote_fields),
-                               $this->handlerInstance[$this->lastHandlerKey]['link']
-                       );
-               }
-               foreach ($rows as $row) {
-                       $fields_values = array();
-                       foreach ($fields as $key => $value) {
-                               $fields_values[$value] = $row[$key];
+                       $res = $this->query(parent::INSERTmultipleRows($table, $fields, $rows, $no_quote_fields));
+               } else {
+                       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);
                        }
-                       $res = $this->exec_INSERTquery($table, $fields_values, $no_quote_fields);
                }
                foreach ($this->postProcessHookObjects as $hookObject) {
                        $hookObject->exec_INSERTmultipleRows_postProcessAction($table, $fields, $rows, $no_quote_fields, $this);
@@ -568,18 +643,17 @@ class DatabaseConnection extends \TYPO3\CMS\Core\Database\DatabaseConnection {
        }
 
        /**
-        * Updates a record from $table
+        * Creates and executes an UPDATE SQL-statement for $table where $where-clause (typ. 'uid=...') from the array with field/value pairs $fields_values.
+        * Using this function specifically allow us to handle BLOB and CLOB fields depending on DB
         *
-        * @param       string          Database tablename
-        * @param       string          WHERE clause, eg. "uid=1". NOTICE: You must escape values in this argument with $this->fullQuoteStr() yourself!
-        * @param       array           Field values as key=>value pairs. Values will be escaped internally. Typically you would fill an array like "$updateFields" with 'fieldname'=>'value' and pass it to this function as argument.
-        * @param mixed List/array of keys NOT to quote (eg. SQL functions)
-        * @return      mixed           Result from handler, usually TRUE when success and FALSE on failure
+        * @param string $table Database tablename
+        * @param string $where WHERE clause, eg. "uid=1". NOTICE: You must escape values in this argument with $this->fullQuoteStr() yourself!
+        * @param array $fields_values Field values as key=>value pairs. Values will be escaped internally. Typically you would fill an array like "$updateFields" with 'fieldname'=>'value' and pass it to this function as argument.
+        * @param bool|array|string $no_quote_fields See fullQuoteArray()
+        * @return bool|\mysqli_result|object MySQLi result object / DBAL object
         */
-       public function exec_UPDATEquery($table, $where, $fields_values, $no_quote_fields = '') {
-               if ($this->debug) {
-                       $pt = \TYPO3\CMS\Core\Utility\GeneralUtility::milliseconds();
-               }
+       public function exec_UPDATEquery($table, $where, $fields_values, $no_quote_fields = FALSE) {
+               $pt = $this->debug ? GeneralUtility::milliseconds() : 0;
                // Do table/field mapping:
                $ORIG_tableName = $table;
                if ($tableArray = $this->map_needMapping($table)) {
@@ -596,53 +670,52 @@ class DatabaseConnection extends \TYPO3\CMS\Core\Database\DatabaseConnection {
                }
                // Select API
                $this->lastHandlerKey = $this->handler_getFromTableList($table);
-               $hType = (string) $this->handlerCfg[$this->lastHandlerKey]['type'];
+               $hType = (string)$this->handlerCfg[$this->lastHandlerKey]['type'];
+               $sqlResult = NULL;
                switch ($hType) {
-               case 'native':
-                       if ($this->lastHandlerKey === '_DEFAULT' && !$this->isConnected()) {
-                               $this->connectDB();
-                       }
-                       $this->lastQuery = $this->UPDATEquery($table, $where, $fields_values, $no_quote_fields);
-                       if (is_string($this->lastQuery)) {
-                               $sqlResult = mysql_query($this->lastQuery, $this->handlerInstance[$this->lastHandlerKey]['link']);
-                       } else {
-                               $sqlResult = mysql_query($this->lastQuery[0], $this->handlerInstance[$this->lastHandlerKey]['link']);
-                               foreach ($this->lastQuery[1] as $field => $content) {
-                                       mysql_query('UPDATE ' . $this->quoteFromTables($table) . ' SET ' . $this->quoteFromTables($field) . '=' . $this->fullQuoteStr($content, $table) . ' WHERE ' . $this->quoteWhereClause($where), $this->handlerInstance[$this->lastHandlerKey]['link']);
-                               }
-                       }
-                       break;
-               case 'adodb':
-                       $this->lastQuery = $this->UPDATEquery($table, $where, $fields_values, $no_quote_fields);
-                       if (is_string($this->lastQuery)) {
-                               $sqlResult = $this->handlerInstance[$this->lastHandlerKey]->_query($this->lastQuery, FALSE);
-                       } else {
-                               $this->handlerInstance[$this->lastHandlerKey]->StartTrans();
-                               if (strlen($this->lastQuery[0])) {
-                                       $sqlResult = $this->handlerInstance[$this->lastHandlerKey]->_query($this->lastQuery[0], FALSE);
-                               }
-                               if (is_array($this->lastQuery[1])) {
+                       case 'native':
+                               $this->lastQuery = $this->UPDATEquery($table, $where, $fields_values, $no_quote_fields);
+                               if (is_string($this->lastQuery)) {
+                                       $sqlResult = $this->query($this->lastQuery);
+                               } else {
+                                       $sqlResult = $this->query($this->lastQuery[0]);
                                        foreach ($this->lastQuery[1] as $field => $content) {
-                                               $this->handlerInstance[$this->lastHandlerKey]->UpdateBlob($this->quoteFromTables($table), $field, $content, $this->quoteWhereClause($where));
+                                               $stmt = 'UPDATE ' . $this->quoteFromTables($table) . ' SET ' . $this->quoteFromTables($field) . '=' . $this->fullQuoteStr($content, $table, TRUE) . ' WHERE ' . $this->quoteWhereClause($where);
+                                               $this->query($stmt);
                                        }
                                }
-                               if (is_array($this->lastQuery[2])) {
-                                       foreach ($this->lastQuery[2] as $field => $content) {
-                                               $this->handlerInstance[$this->lastHandlerKey]->UpdateClob($this->quoteFromTables($table), $field, $content, $this->quoteWhereClause($where));
+                               break;
+                       case 'adodb':
+                               $this->lastQuery = $this->UPDATEquery($table, $where, $fields_values, $no_quote_fields);
+                               if (is_string($this->lastQuery)) {
+                                       $sqlResult = $this->handlerInstance[$this->lastHandlerKey]->_query($this->lastQuery, FALSE);
+                               } else {
+                                       $this->handlerInstance[$this->lastHandlerKey]->StartTrans();
+                                       if ((string)$this->lastQuery[0] !== '') {
+                                               $sqlResult = $this->handlerInstance[$this->lastHandlerKey]->_query($this->lastQuery[0], FALSE);
+                                       }
+                                       if (is_array($this->lastQuery[1])) {
+                                               foreach ($this->lastQuery[1] as $field => $content) {
+                                                       $this->handlerInstance[$this->lastHandlerKey]->UpdateBlob($this->quoteFromTables($table), $field, $content, $this->quoteWhereClause($where));
+                                               }
+                                       }
+                                       if (is_array($this->lastQuery[2])) {
+                                               foreach ($this->lastQuery[2] as $field => $content) {
+                                                       $this->handlerInstance[$this->lastHandlerKey]->UpdateClob($this->quoteFromTables($table), $field, $content, $this->quoteWhereClause($where));
+                                               }
                                        }
+                                       $this->handlerInstance[$this->lastHandlerKey]->CompleteTrans();
                                }
-                               $this->handlerInstance[$this->lastHandlerKey]->CompleteTrans();
-                       }
-                       break;
-               case 'userdefined':
-                       $sqlResult = $this->handlerInstance[$this->lastHandlerKey]->exec_UPDATEquery($table, $where, $fields_values, $no_quote_fields);
-                       break;
+                               break;
+                       case 'userdefined':
+                               $sqlResult = $this->handlerInstance[$this->lastHandlerKey]->exec_UPDATEquery($table, $where, $fields_values, $no_quote_fields);
+                               break;
                }
                if ($this->printErrors && $this->sql_error()) {
                        debug(array($this->lastQuery, $this->sql_error()));
                }
                if ($this->debug) {
-                       $this->debugHandler('exec_UPDATEquery', \TYPO3\CMS\Core\Utility\GeneralUtility::milliseconds() - $pt, array(
+                       $this->debugHandler('exec_UPDATEquery', GeneralUtility::milliseconds() - $pt, array(
                                'handlerType' => $hType,
                                'args' => array($table, $where, $fields_values),
                                'ORIG_from_table' => $ORIG_tableName
@@ -656,16 +729,14 @@ class DatabaseConnection extends \TYPO3\CMS\Core\Database\DatabaseConnection {
        }
 
        /**
-        * Deletes records from table
+        * Creates and executes a DELETE SQL-statement for $table where $where-clause
         *
-        * @param       string          Database tablename
-        * @param       string          WHERE clause, eg. "uid=1". NOTICE: You must escape values in this argument with $this->fullQuoteStr() yourself!
-        * @return      mixed           Result from handler
+        * @param string $table Database tablename
+        * @param string $where WHERE clause, eg. "uid=1". NOTICE: You must escape values in this argument with $this->fullQuoteStr() yourself!
+        * @return bool|\mysqli_result|object MySQLi result object / DBAL object
         */
        public function exec_DELETEquery($table, $where) {
-               if ($this->debug) {
-                       $pt = \TYPO3\CMS\Core\Utility\GeneralUtility::milliseconds();
-               }
+               $pt = $this->debug ? GeneralUtility::milliseconds() : 0;
                // Do table/field mapping:
                $ORIG_tableName = $table;
                if ($tableArray = $this->map_needMapping($table)) {
@@ -680,28 +751,26 @@ class DatabaseConnection extends \TYPO3\CMS\Core\Database\DatabaseConnection {
                }
                // Select API
                $this->lastHandlerKey = $this->handler_getFromTableList($table);
-               $hType = (string) $this->handlerCfg[$this->lastHandlerKey]['type'];
+               $hType = (string)$this->handlerCfg[$this->lastHandlerKey]['type'];
+               $sqlResult = NULL;
                switch ($hType) {
-               case 'native':
-                       if ($this->lastHandlerKey === '_DEFAULT' && !$this->isConnected()) {
-                               $this->connectDB();
-                       }
-                       $this->lastQuery = $this->DELETEquery($table, $where);
-                       $sqlResult = mysql_query($this->lastQuery, $this->handlerInstance[$this->lastHandlerKey]['link']);
-                       break;
-               case 'adodb':
-                       $this->lastQuery = $this->DELETEquery($table, $where);
-                       $sqlResult = $this->handlerInstance[$this->lastHandlerKey]->_query($this->lastQuery, FALSE);
-                       break;
-               case 'userdefined':
-                       $sqlResult = $this->handlerInstance[$this->lastHandlerKey]->exec_DELETEquery($table, $where);
-                       break;
+                       case 'native':
+                               $this->lastQuery = $this->DELETEquery($table, $where);
+                               $sqlResult = $this->query($this->lastQuery);
+                               break;
+                       case 'adodb':
+                               $this->lastQuery = $this->DELETEquery($table, $where);
+                               $sqlResult = $this->handlerInstance[$this->lastHandlerKey]->_query($this->lastQuery, FALSE);
+                               break;
+                       case 'userdefined':
+                               $sqlResult = $this->handlerInstance[$this->lastHandlerKey]->exec_DELETEquery($table, $where);
+                               break;
                }
                if ($this->printErrors && $this->sql_error()) {
                        debug(array($this->lastQuery, $this->sql_error()));
                }
                if ($this->debug) {
-                       $this->debugHandler('exec_DELETEquery', \TYPO3\CMS\Core\Utility\GeneralUtility::milliseconds() - $pt, array(
+                       $this->debugHandler('exec_DELETEquery', GeneralUtility::milliseconds() - $pt, array(
                                'handlerType' => $hType,
                                'args' => array($table, $where),
                                'ORIG_from_table' => $ORIG_tableName
@@ -715,20 +784,20 @@ class DatabaseConnection extends \TYPO3\CMS\Core\Database\DatabaseConnection {
        }
 
        /**
-        * Selects records from Data Source
+        * Creates and executes a SELECT SQL-statement
+        * Using this function specifically allow us to handle the LIMIT feature independently of DB.
         *
-        * @param       string $select_fields List of fields to select from the table. This is what comes right after "SELECT ...". Required value.
-        * @param       string $from_table Table(s) from which to select. This is what comes right after "FROM ...". Required value.
-        * @param       string $where_clause Optional additional WHERE clauses put in the end of the query. NOTICE: You must escape values in this argument with $this->fullQquoteStr() yourself! DO NOT PUT IN GROUP BY, ORDER BY or LIMIT!
-        * @param       string $groupBy Optional GROUP BY field(s), if none, supply blank string.
-        * @param       string $orderBy Optional ORDER BY field(s), if none, supply blank string.
-        * @param       string $limit Optional LIMIT value ([begin,]max), if none, supply blank string.
-        * @return      mixed           Result from handler. Typically object from DBAL layers.
+        * @param string $select_fields List of fields to select from the table. This is what comes right after "SELECT ...". Required value.
+        * @param string $from_table Table(s) from which to select. This is what comes right after "FROM ...". Required value.
+        * @param string $where_clause Additional WHERE clauses put in the end of the query. NOTICE: You must escape values in this argument with $this->fullQuoteStr() yourself! DO NOT PUT IN GROUP BY, ORDER BY or LIMIT!
+        * @param string $groupBy Optional GROUP BY field(s), if none, supply blank string.
+        * @param string $orderBy Optional ORDER BY field(s), if none, supply blank string.
+        * @param string $limit Optional LIMIT value ([begin,]max), if none, supply blank string.
+        * @throws \RuntimeException
+        * @return bool|\mysqli_result|object MySQLi result object / DBAL object
         */
        public function exec_SELECTquery($select_fields, $from_table, $where_clause, $groupBy = '', $orderBy = '', $limit = '') {
-               if ($this->debug) {
-                       $pt = \TYPO3\CMS\Core\Utility\GeneralUtility::milliseconds();
-               }
+               $pt = $this->debug ? GeneralUtility::milliseconds() : 0;
                // Map table / field names if needed:
                $ORIG_tableName = $from_table;
                // Saving table names in $ORIG_from_table since $from_table is transformed beneath:
@@ -739,67 +808,68 @@ class DatabaseConnection extends \TYPO3\CMS\Core\Database\DatabaseConnection {
                        $remappedParameters = $this->map_remapSELECTQueryParts($select_fields, $from, $where_clause, $groupBy, $orderBy);
                }
                // Get handler key and select API:
-               if (count($remappedParameters) > 0) {
+               if (!empty($remappedParameters)) {
                        $mappedQueryParts = $this->compileSelectParameters($remappedParameters);
                        $fromTable = $mappedQueryParts[1];
                } else {
                        $fromTable = $from_table;
                }
                $this->lastHandlerKey = $this->handler_getFromTableList($fromTable);
-               $hType = (string) $this->handlerCfg[$this->lastHandlerKey]['type'];
+               $hType = (string)$this->handlerCfg[$this->lastHandlerKey]['type'];
+               $sqlResult = NULL;
                switch ($hType) {
-               case 'native':
-                       if ($this->lastHandlerKey === '_DEFAULT' && !$this->isConnected()) {
-                               $this->connectDB();
-                       }
-                       if (count($remappedParameters) > 0) {
-                               list($select_fields, $from_table, $where_clause, $groupBy, $orderBy) = $this->compileSelectParameters($remappedParameters);
-                       }
-                       $this->lastQuery = $this->SELECTquery($select_fields, $from_table, $where_clause, $groupBy, $orderBy, $limit);
-                       $sqlResult = mysql_query($this->lastQuery, $this->handlerInstance[$this->lastHandlerKey]['link']);
-                       $this->resourceIdToTableNameMap[(string) $sqlResult] = $ORIG_tableName;
-                       break;
-               case 'adodb':
-                       if ($limit != '') {
-                               $splitLimit = \TYPO3\CMS\Core\Utility\GeneralUtility::intExplode(',', $limit);
-                               // Splitting the limit values:
-                               if ($splitLimit[1]) {
-                                       // If there are two parameters, do mapping differently than otherwise:
-                                       $numrows = $splitLimit[1];
-                                       $offset = $splitLimit[0];
-                               } else {
-                                       $numrows = $splitLimit[0];
-                                       $offset = 0;
+                       case 'native':
+                               if (!empty($remappedParameters)) {
+                                       list($select_fields, $from_table, $where_clause, $groupBy, $orderBy) = $this->compileSelectParameters($remappedParameters);
                                }
-                               if (count($remappedParameters) > 0) {
-                                       $sqlResult = $this->handlerInstance[$this->lastHandlerKey]->SelectLimit($this->SELECTqueryFromArray($remappedParameters), $numrows, $offset);
+                               $this->lastQuery = $this->SELECTquery($select_fields, $from_table, $where_clause, $groupBy, $orderBy, $limit);
+                               $sqlResult = $this->query($this->lastQuery);
+                               $this->resourceIdToTableNameMap[serialize($sqlResult)] = $ORIG_tableName;
+                               break;
+                       case 'adodb':
+                               if ($limit != '') {
+                                       $splitLimit = GeneralUtility::intExplode(',', $limit);
+                                       // Splitting the limit values:
+                                       if ($splitLimit[1]) {
+                                               // If there are two parameters, do mapping differently than otherwise:
+                                               $numrows = $splitLimit[1];
+                                               $offset = $splitLimit[0];
+                                       } else {
+                                               $numrows = $splitLimit[0];
+                                               $offset = 0;
+                                       }
+                                       if (!empty($remappedParameters)) {
+                                               $sqlResult = $this->handlerInstance[$this->lastHandlerKey]->SelectLimit($this->SELECTqueryFromArray($remappedParameters), $numrows, $offset);
+                                       } else {
+                                               $sqlResult = $this->handlerInstance[$this->lastHandlerKey]->SelectLimit($this->SELECTquery($select_fields, $from_table, $where_clause, $groupBy, $orderBy), $numrows, $offset);
+                                       }
+                                       $this->lastQuery = $sqlResult->sql;
                                } else {
-                                       $sqlResult = $this->handlerInstance[$this->lastHandlerKey]->SelectLimit($this->SELECTquery($select_fields, $from_table, $where_clause, $groupBy, $orderBy), $numrows, $offset);
+                                       if (!empty($remappedParameters)) {
+                                               $this->lastQuery = $this->SELECTqueryFromArray($remappedParameters);
+                                       } else {
+                                               $this->lastQuery = $this->SELECTquery($select_fields, $from_table, $where_clause, $groupBy, $orderBy);
+                                       }
+                                       $sqlResult = $this->handlerInstance[$this->lastHandlerKey]->_Execute($this->lastQuery);
                                }
-                               $this->lastQuery = $sqlResult->sql;
-                       } else {
-                               if (count($remappedParameters) > 0) {
-                                       $this->lastQuery = $this->SELECTqueryFromArray($remappedParameters);
-                               } else {
-                                       $this->lastQuery = $this->SELECTquery($select_fields, $from_table, $where_clause, $groupBy, $orderBy);
+                               if (!is_object($sqlResult)) {
+                                       throw new \RuntimeException('ADOdb could not run this query: ' . $this->lastQuery, 1421053336);
                                }
-                               $sqlResult = $this->handlerInstance[$this->lastHandlerKey]->_Execute($this->lastQuery);
-                       }
-                       $sqlResult->TYPO3_DBAL_handlerType = 'adodb';
-                       // Setting handler type in result object (for later recognition!)
-                       $sqlResult->TYPO3_DBAL_tableList = $ORIG_tableName;
-                       break;
-               case 'userdefined':
-                       if (count($remappedParameters) > 0) {
-                               list($select_fields, $from_table, $where_clause, $groupBy, $orderBy) = $this->compileSelectParameters($remappedParameters);
-                       }
-                       $sqlResult = $this->handlerInstance[$this->lastHandlerKey]->exec_SELECTquery($select_fields, $from_table, $where_clause, $groupBy, $orderBy, $limit);
-                       if (is_object($sqlResult)) {
-                               $sqlResult->TYPO3_DBAL_handlerType = 'userdefined';
+                               $sqlResult->TYPO3_DBAL_handlerType = 'adodb';
                                // Setting handler type in result object (for later recognition!)
                                $sqlResult->TYPO3_DBAL_tableList = $ORIG_tableName;
-                       }
-                       break;
+                               break;
+                       case 'userdefined':
+                               if (!empty($remappedParameters)) {
+                                       list($select_fields, $from_table, $where_clause, $groupBy, $orderBy) = $this->compileSelectParameters($remappedParameters);
+                               }
+                               $sqlResult = $this->handlerInstance[$this->lastHandlerKey]->exec_SELECTquery($select_fields, $from_table, $where_clause, $groupBy, $orderBy, $limit);
+                               if (is_object($sqlResult)) {
+                                       $sqlResult->TYPO3_DBAL_handlerType = 'userdefined';
+                                       // Setting handler type in result object (for later recognition!)
+                                       $sqlResult->TYPO3_DBAL_tableList = $ORIG_tableName;
+                               }
+                               break;
                }
                if ($this->printErrors && $this->sql_error()) {
                        debug(array($this->lastQuery, $this->sql_error()));
@@ -813,22 +883,20 @@ class DatabaseConnection extends \TYPO3\CMS\Core\Database\DatabaseConnection {
                        if ($this->conf['debugOptions']['numberRows']) {
                                $data['numberRows'] = $this->sql_num_rows($sqlResult);
                        }
-                       $this->debugHandler('exec_SELECTquery', \TYPO3\CMS\Core\Utility\GeneralUtility::milliseconds() - $pt, $data);
+                       $this->debugHandler('exec_SELECTquery', GeneralUtility::milliseconds() - $pt, $data);
                }
-               // Return result handler.
+               // Return handler.
                return $sqlResult;
        }
 
        /**
         * Truncates a table.
         *
-        * @param       string          Database tablename
-        * @return      mixed           Result from handler
+        * @param string $table Database tablename
+        * @return mixed Result from handler
         */
        public function exec_TRUNCATEquery($table) {
-               if ($this->debug) {
-                       $pt = \TYPO3\CMS\Core\Utility\GeneralUtility::milliseconds();
-               }
+               $pt = $this->debug ? GeneralUtility::milliseconds() : 0;
                // Do table/field mapping:
                $ORIG_tableName = $table;
                if ($tableArray = $this->map_needMapping($table)) {
@@ -839,28 +907,26 @@ class DatabaseConnection extends \TYPO3\CMS\Core\Database\DatabaseConnection {
                }
                // Select API
                $this->lastHandlerKey = $this->handler_getFromTableList($table);
-               $hType = (string) $this->handlerCfg[$this->lastHandlerKey]['type'];
+               $hType = (string)$this->handlerCfg[$this->lastHandlerKey]['type'];
+               $sqlResult = NULL;
                switch ($hType) {
-               case 'native':
-                       if ($this->lastHandlerKey === '_DEFAULT' && !$this->isConnected()) {
-                               $this->connectDB();
-                       }
-                       $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);
-                       break;
+                       case 'native':
+                               $this->lastQuery = $this->TRUNCATEquery($table);
+                               $sqlResult = $this->query($this->lastQuery);
+                               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);
+                               break;
                }
                if ($this->printErrors && $this->sql_error()) {
                        debug(array($this->lastQuery, $this->sql_error()));
                }
                if ($this->debug) {
-                       $this->debugHandler('exec_TRUNCATEquery', \TYPO3\CMS\Core\Utility\GeneralUtility::milliseconds() - $pt, array(
+                       $this->debugHandler('exec_TRUNCATEquery', GeneralUtility::milliseconds() - $pt, array(
                                'handlerType' => $hType,
                                'args' => array($table),
                                'ORIG_from_table' => $ORIG_tableName
@@ -877,51 +943,67 @@ class DatabaseConnection extends \TYPO3\CMS\Core\Database\DatabaseConnection {
         * Executes a query.
         * EXPERIMENTAL since TYPO3 4.4.
         *
-        * @param array $queryParts SQL parsed by method parseSQL() of \TYPO3\CMS\Core\Database\SqlParser
-        * @return pointer Result pointer / DBAL object
+        * @param array $queryParts SQL parsed by method parseSQL() of \TYPO3\CMS\Dbal\Database\SqlParser
+        * @return \mysqli_result|object MySQLi result object / DBAL object
         * @see self::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->compileFieldList($queryParts['GROUPBY']) : '';
-                       $orderBy = isset($queryParts['ORDERBY']) ? $this->SQLparser->compileFieldList($queryParts['ORDERBY']) : '';
-                       $limit = isset($queryParts['LIMIT']) ? $queryParts['LIMIT'] : '';
-                       return $this->exec_SELECTquery($selectFields, $fromTables, $whereClause, $groupBy, $orderBy, $limit);
-               case 'UPDATE':
-                       $table = $queryParts['TABLE'];
-                       $fields = array();
-                       foreach ($queryParts['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 {
+                       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->compileFieldList($queryParts['GROUPBY']) : '';
+                               $orderBy = isset($queryParts['ORDERBY']) ? $this->SQLparser->compileFieldList($queryParts['ORDERBY']) : '';
+                               $limit = isset($queryParts['LIMIT']) ? $queryParts['LIMIT'] : '';
+                               return $this->exec_SELECTquery($selectFields, $fromTables, $whereClause, $groupBy, $orderBy, $limit);
+                       case 'UPDATE':
+                               $table = $queryParts['TABLE'];
+                               $fields = array();
                                foreach ($queryParts['FIELDS'] as $fN => $fV) {
-                                       $values[$fN] = $fV[0];
+                                       $fields[$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);
+                               $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);
+                       default:
+                               return NULL;
+               }
+       }
+
+       /**
+        * Central query method. Also checks if there is a database connection.
+        * Use this to execute database queries instead of directly calling $this->link->query()
+        *
+        * @param string $query The query to send to the database
+        * @return bool|\mysqli_result
+        */
+       protected function query($query) {
+               if (!$this->isConnected()) {
+                       $this->connectDB();
                }
+               return $this->handlerInstance[$this->lastHandlerKey]['link']->query($query);
        }
 
        /**************************************
@@ -931,69 +1013,52 @@ class DatabaseConnection extends \TYPO3\CMS\Core\Database\DatabaseConnection {
         **************************************/
        /**
         * Creates an INSERT SQL-statement for $table from the array with field/value pairs $fields_values.
-        * Usage count/core: 4
         *
-        * @param       string          See exec_INSERTquery()
-        * @param       array           See exec_INSERTquery()
-        * @param mixed         See exec_INSERTquery()
-        * @return      mixed           Full SQL query for INSERT as string or array (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, where 0 => plain SQL, 1 => fieldname/value pairs of BLOB fields
+        * @param string $table See exec_INSERTquery()
+        * @param array $fields_values See exec_INSERTquery()
+        * @param bool|array|string $no_quote_fields See fullQuoteArray()
+        * @return string|NULL Full SQL query for INSERT, NULL if $rows is empty
         */
-       public function INSERTquery($table, $fields_values, $no_quote_fields = '') {
+       public function INSERTquery($table, $fields_values, $no_quote_fields = FALSE) {
                // Table and fieldnames should be "SQL-injection-safe" when supplied to this function (contrary to values in the arrays which may be insecure).
-               if (is_array($fields_values) && count($fields_values)) {
-                       foreach ($this->preProcessHookObjects as $hookObject) {
-                               $hookObject->INSERTquery_preProcessAction($table, $fields_values, $no_quote_fields, $this);
-                       }
-                       if (is_string($no_quote_fields)) {
-                               $no_quote_fields = explode(',', $no_quote_fields);
-                       } elseif (!is_array($no_quote_fields)) {
-                               $no_quote_fields = array();
-                       }
-                       $blobfields = array();
-                       $nArr = array();
-                       $handlerKey = $this->handler_getFromTableList($table);
-                       $quoteClob = isset($this->handlerCfg[$handlerKey]['config']['quoteClob']) ? $this->handlerCfg[$handlerKey]['config']['quoteClob'] : FALSE;
-                       foreach ($fields_values as $k => $v) {
-                               if (!$this->runningNative() && $this->sql_field_metatype($table, $k) == 'B') {
-                                       // we skip the field in the regular INSERT statement, it is only in blobfields
-                                       $blobfields[$this->quoteFieldNames($k)] = $v;
-                               } elseif (!$this->runningNative() && $this->sql_field_metatype($table, $k) == 'XL') {
-                                       // we skip the field in the regular INSERT statement, it is only in clobfields
-                                       $clobfields[$this->quoteFieldNames($k)] = $quoteClob ? $this->quoteStr($v, $table) : $v;
-                               } else {
-                                       // Add slashes old-school:
-                                       // cast numerical values
-                                       $mt = $this->sql_field_metatype($table, $k);
-                                       if ($mt[0] == 'I') {
-                                               $v = (int) $v;
-                                       } elseif ($mt[0] == 'F') {
-                                               $v = (double) $v;
-                                       }
-                                       $nArr[$this->quoteFieldNames($k)] = !in_array($k, $no_quote_fields) ? $this->fullQuoteStr($v, $table) : $v;
+               if (!is_array($fields_values) || empty($fields_values)) {
+                       return '';
+               }
+               foreach ($this->preProcessHookObjects as $hookObject) {
+                       $hookObject->INSERTquery_preProcessAction($table, $fields_values, $no_quote_fields, $this);
+               }
+               if (is_string($no_quote_fields)) {
+                       $no_quote_fields = explode(',', $no_quote_fields);
+               } elseif (!is_array($no_quote_fields)) {
+                       $no_quote_fields = array();
+               }
+               $blobFields = $clobFields = array();
+               $nArr = array();
+               $handlerKey = $this->handler_getFromTableList($table);
+               $quoteClob = isset($this->handlerCfg[$handlerKey]['config']['quoteClob']) ? $this->handlerCfg[$handlerKey]['config']['quoteClob'] : FALSE;
+               foreach ($fields_values as $k => $v) {
+                       if (!$this->runningNative() && $this->sql_field_metatype($table, $k) == 'B') {
+                               // we skip the field in the regular INSERT statement, it is only in blobfields
+                               $blobFields[$this->quoteFieldNames($k)] = $v;
+                       } elseif (!$this->runningNative() && $this->sql_field_metatype($table, $k) == 'XL') {
+                               // we skip the field in the regular INSERT statement, it is only in clobfields
+                               $clobFields[$this->quoteFieldNames($k)] = $quoteClob ? $this->quoteStr($v, $table) : $v;
+                       } else {
+                               // Add slashes old-school:
+                               // cast numerical values
+                               $mt = $this->sql_field_metatype($table, $k);
+                               if ($mt[0] == 'I') {
+                                       $v = (int)$v;
+                               } elseif ($mt[0] == 'F') {
+                                       $v = (double) $v;
                                }
+                               $nArr[$this->quoteFieldNames($k)] = !in_array($k, $no_quote_fields) ? $this->fullQuoteStr($v, $table, TRUE) : $v;
                        }
-                       if (count($blobfields) || count($clobfields)) {
-                               if (count($nArr)) {
-                                       $query[0] = 'INSERT INTO ' . $this->quoteFromTables($table) . '
-                                       (
-                                               ' . implode(',
-                                               ', array_keys($nArr)) . '
-                                       ) VALUES (
-                                               ' . implode(',
-                                               ', $nArr) . '
-                                       )';
-                               }
-                               if (count($blobfields)) {
-                                       $query[1] = $blobfields;
-                               }
-                               if (count($clobfields)) {
-                                       $query[2] = $clobfields;
-                               }
-                               if ($this->debugOutput || $this->store_lastBuiltQuery) {
-                                       $this->debug_lastBuiltQuery = $query[0];
-                               }
-                       } else {
-                               $query = 'INSERT INTO ' . $this->quoteFromTables($table) . '
+               }
+               if (!empty($blobFields) || !empty($clobFields)) {
+                       $query = array();
+                       if (!empty($nArr)) {
+                               $query[0] = 'INSERT INTO ' . $this->quoteFromTables($table) . '
                                (
                                        ' . implode(',
                                        ', array_keys($nArr)) . '
@@ -1001,26 +1066,43 @@ class DatabaseConnection extends \TYPO3\CMS\Core\Database\DatabaseConnection {
                                        ' . implode(',
                                        ', $nArr) . '
                                )';
-                               if ($this->debugOutput || $this->store_lastBuiltQuery) {
-                                       $this->debug_lastBuiltQuery = $query;
-                               }
                        }
-                       return $query;
+                       if (!empty($blobFields)) {
+                               $query[1] = $blobFields;
+                       }
+                       if (!empty($clobFields)) {
+                               $query[2] = $clobFields;
+                       }
+                       if (isset($query[0]) && ($this->debugOutput || $this->store_lastBuiltQuery)) {
+                               $this->debug_lastBuiltQuery = $query[0];
+                       }
+               } else {
+                       $query = 'INSERT INTO ' . $this->quoteFromTables($table) . '
+                       (
+                               ' . implode(',
+                               ', array_keys($nArr)) . '
+                       ) VALUES (
+                               ' . implode(',
+                               ', $nArr) . '
+                       )';
+                       if ($this->debugOutput || $this->store_lastBuiltQuery) {
+                               $this->debug_lastBuiltQuery = $query;
+                       }
                }
+               return $query;
        }
 
        /**
         * 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.
+        * @param string $table Table name
+        * @param array $fields Field names
+        * @param array $rows Table rows. Each row should be an array with field values mapping to $fields
+        * @param bool|array|string $no_quote_fields See fullQuoteArray()
+        * @return string|array Full SQL query for INSERT (unless $rows does not contain any elements in which case it will be FALSE)
         */
        public function INSERTmultipleRows($table, array $fields, array $rows, $no_quote_fields = FALSE) {
-               if ((string) $this->handlerCfg[$this->lastHandlerKey]['type'] === 'native') {
+               if ((string)$this->handlerCfg[$this->lastHandlerKey]['type'] === 'native') {
                        return parent::INSERTmultipleRows($table, $fields, $rows, $no_quote_fields);
                }
                $result = array();
@@ -1041,75 +1123,75 @@ class DatabaseConnection extends \TYPO3\CMS\Core\Database\DatabaseConnection {
 
        /**
         * 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
         *
-        * @param       string          See exec_UPDATEquery()
-        * @param       string          See exec_UPDATEquery()
-        * @param       array           See exec_UPDATEquery()
-        * @param       mixed           See exec_UPDATEquery()
-        * @return      mixed           Full SQL query for UPDATE as string or array (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, where 0 => plain SQL, 1 => fieldname/value pairs of BLOB fields
+        *
+        * @param string $table See exec_UPDATEquery()
+        * @param string $where See exec_UPDATEquery()
+        * @param array $fields_values See exec_UPDATEquery()
+        * @param bool|array|string $no_quote_fields See fullQuoteArray()
+        * @throws \InvalidArgumentException
+        * @return string Full SQL query for UPDATE
         */
-       public function UPDATEquery($table, $where, $fields_values, $no_quote_fields = '') {
+       public function UPDATEquery($table, $where, $fields_values, $no_quote_fields = FALSE) {
                // Table and fieldnames should be "SQL-injection-safe" when supplied to this function (contrary to values in the arrays which may be insecure).
                if (is_string($where)) {
                        foreach ($this->preProcessHookObjects as $hookObject) {
                                $hookObject->UPDATEquery_preProcessAction($table, $where, $fields_values, $no_quote_fields, $this);
                        }
-                       $fields = array();
-                       $blobfields = array();
-                       $clobfields = array();
-                       if (is_array($fields_values) && count($fields_values)) {
+                       $blobFields = $clobFields = array();
+                       $nArr = array();
+                       if (is_array($fields_values) && !empty($fields_values)) {
                                if (is_string($no_quote_fields)) {
                                        $no_quote_fields = explode(',', $no_quote_fields);
                                } elseif (!is_array($no_quote_fields)) {
                                        $no_quote_fields = array();
                                }
-                               $nArr = array();
                                $handlerKey = $this->handler_getFromTableList($table);
                                $quoteClob = isset($this->handlerCfg[$handlerKey]['config']['quoteClob']) ? $this->handlerCfg[$handlerKey]['config']['quoteClob'] : FALSE;
                                foreach ($fields_values as $k => $v) {
                                        if (!$this->runningNative() && $this->sql_field_metatype($table, $k) == 'B') {
                                                // we skip the field in the regular UPDATE statement, it is only in blobfields
-                                               $blobfields[$this->quoteFieldNames($k)] = $v;
+                                               $blobFields[$this->quoteFieldNames($k)] = $v;
                                        } elseif (!$this->runningNative() && $this->sql_field_metatype($table, $k) == 'XL') {
                                                // we skip the field in the regular UPDATE statement, it is only in clobfields
-                                               $clobfields[$this->quoteFieldNames($k)] = $quoteClob ? $this->quoteStr($v, $table) : $v;
+                                               $clobFields[$this->quoteFieldNames($k)] = $quoteClob ? $this->quoteStr($v, $table) : $v;
                                        } else {
                                                // Add slashes old-school:
                                                // cast numeric values
                                                $mt = $this->sql_field_metatype($table, $k);
                                                if ($mt[0] == 'I') {
-                                                       $v = (int) $v;
+                                                       $v = (int)$v;
                                                } elseif ($mt[0] == 'F') {
                                                        $v = (double) $v;
                                                }
-                                               $nArr[] = $this->quoteFieldNames($k) . '=' . (!in_array($k, $no_quote_fields) ? $this->fullQuoteStr($v, $table) : $v);
+                                               $nArr[] = $this->quoteFieldNames($k) . '=' . (!in_array($k, $no_quote_fields) ? $this->fullQuoteStr($v, $table, TRUE) : $v);
                                        }
                                }
                        }
-                       if (count($blobfields) || count($clobfields)) {
-                               if (count($nArr)) {
+                       if (!empty($blobFields) || !empty($clobFields)) {
+                               $query = array();
+                               if (!empty($nArr)) {
                                        $query[0] = 'UPDATE ' . $this->quoteFromTables($table) . '
                                                SET
                                                        ' . implode(',
-                                                       ', $nArr) . (strlen($where) > 0 ? '
+                                                       ', $nArr) . ($where !== '' ? '
                                                WHERE
                                                        ' . $this->quoteWhereClause($where) : '');
                                }
-                               if (count($blobfields)) {
-                                       $query[1] = $blobfields;
+                               if (!empty($blobFields)) {
+                                       $query[1] = $blobFields;
                                }
-                               if (count($clobfields)) {
-                                       $query[2] = $clobfields;
+                               if (!empty($clobFields)) {
+                                       $query[2] = $clobFields;
                                }
-                               if ($this->debugOutput || $this->store_lastBuiltQuery) {
+                               if (isset($query[0]) && ($this->debugOutput || $this->store_lastBuiltQuery)) {
                                        $this->debug_lastBuiltQuery = $query[0];
                                }
                        } else {
                                $query = 'UPDATE ' . $this->quoteFromTables($table) . '
                                        SET
                                                ' . implode(',
-                                               ', $nArr) . (strlen($where) > 0 ? '
+                                               ', $nArr) . ($where !== '' ? '
                                        WHERE
                                                ' . $this->quoteWhereClause($where) : '');
                                if ($this->debugOutput || $this->store_lastBuiltQuery) {
@@ -1118,17 +1200,17 @@ class DatabaseConnection extends \TYPO3\CMS\Core\Database\DatabaseConnection {
                        }
                        return $query;
                } else {
-                       throw new \InvalidArgumentException('TYPO3 Fatal Error: "Where" clause argument for UPDATE query was not a string in $this->UPDATEquery() !', 1270853880);
+                       throw new \InvalidArgumentException('TYPO3 Fatal Error: "Where" clause argument for UPDATE query was not a string in $this->UPDATEquery() !', 1270853887);
                }
        }
 
        /**
         * Creates a DELETE SQL-statement for $table where $where-clause
-        * Usage count/core: 3
         *
-        * @param       string          See exec_DELETEquery()
-        * @param       string          See exec_DELETEquery()
-        * @return      string          Full SQL query for DELETE
+        * @param string $table See exec_DELETEquery()
+        * @param string $where See exec_DELETEquery()
+        * @return string Full SQL query for DELETE
+        * @throws \InvalidArgumentException
         */
        public function DELETEquery($table, $where) {
                if (is_string($where)) {
@@ -1137,7 +1219,7 @@ class DatabaseConnection extends \TYPO3\CMS\Core\Database\DatabaseConnection {
                        }
                        $table = $this->quoteFromTables($table);
                        $where = $this->quoteWhereClause($where);
-                       $query = 'DELETE FROM ' . $table . (strlen($where) > 0 ? ' WHERE ' . $where : '');
+                       $query = 'DELETE FROM ' . $table . ($where !== '' ? ' WHERE ' . $where : '');
                        if ($this->debugOutput || $this->store_lastBuiltQuery) {
                                $this->debug_lastBuiltQuery = $query;
                        }
@@ -1149,22 +1231,21 @@ class DatabaseConnection extends \TYPO3\CMS\Core\Database\DatabaseConnection {
 
        /**
         * Creates a SELECT SQL-statement
-        * Usage count/core: 11
         *
-        * @param       string          See exec_SELECTquery()
-        * @param       string          See exec_SELECTquery()
-        * @param       string          See exec_SELECTquery()
-        * @param       string          See exec_SELECTquery()
-        * @param       string          See exec_SELECTquery()
-        * @param       string          See exec_SELECTquery()
-        * @return      string          Full SQL query for SELECT
+        * @param string $select_fields See exec_SELECTquery()
+        * @param string $from_table See exec_SELECTquery()
+        * @param string $where_clause See exec_SELECTquery()
+        * @param string $groupBy See exec_SELECTquery()
+        * @param string $orderBy See exec_SELECTquery()
+        * @param string $limit See exec_SELECTquery()
+        * @return string Full SQL query for SELECT
         */
        public function SELECTquery($select_fields, $from_table, $where_clause, $groupBy = '', $orderBy = '', $limit = '') {
                $this->lastHandlerKey = $this->handler_getFromTableList($from_table);
-               $hType = (string) $this->handlerCfg[$this->lastHandlerKey]['type'];
+               $hType = (string)$this->handlerCfg[$this->lastHandlerKey]['type'];
                if ($hType === 'adodb' && $this->runningADOdbDriver('postgres')) {
                        // Possibly rewrite the LIMIT to be PostgreSQL-compatible
-                       $splitLimit = \TYPO3\CMS\Core\Utility\GeneralUtility::intExplode(',', $limit);
+                       $splitLimit = GeneralUtility::intExplode(',', $limit);
                        // Splitting the limit values:
                        if ($splitLimit[1]) {
                                // If there are two parameters, do mapping differently than otherwise:
@@ -1178,6 +1259,7 @@ class DatabaseConnection extends \TYPO3\CMS\Core\Database\DatabaseConnection {
                $where_clause = $this->quoteWhereClause($where_clause);
                $groupBy = $this->quoteGroupBy($groupBy);
                $orderBy = $this->quoteOrderBy($orderBy);
+               $this->dbmsSpecifics->transformQueryParts($select_fields, $from_table, $where_clause, $groupBy, $orderBy, $limit);
                // Call parent method to build actual query
                $query = parent::SELECTquery($select_fields, $from_table, $where_clause, $groupBy, $orderBy, $limit);
                if ($this->debugOutput || $this->store_lastBuiltQuery) {
@@ -1189,8 +1271,8 @@ class DatabaseConnection extends \TYPO3\CMS\Core\Database\DatabaseConnection {
        /**
         * Creates a SELECT SQL-statement to be used with an ADOdb backend.
         *
-        * @param       array           parsed parameters: array($select_fields, $from_table, $where_clause, $groupBy, $orderBy)
-        * @return      string          Full SQL query for SELECT
+        * @param array $params parsed parameters: array($select_fields, $from_table, $where_clause, $groupBy, $orderBy)
+        * @return string Full SQL query for SELECT
         */
        protected function SELECTqueryFromArray(array $params) {
                // $select_fields
@@ -1198,19 +1280,20 @@ class DatabaseConnection extends \TYPO3\CMS\Core\Database\DatabaseConnection {
                // $from_table
                $params[1] = $this->_quoteFromTables($params[1]);
                // $where_clause
-               if (count($params[2]) > 0) {
+               if (!empty($params[2])) {
                        $params[2] = $this->_quoteWhereClause($params[2]);
                }
                // $group_by
-               if (count($params[3]) > 0) {
+               if (!empty($params[3])) {
                        $params[3] = $this->_quoteGroupBy($params[3]);
                }
                // $order_by
-               if (count($params[4]) > 0) {
+               if (!empty($params[4])) {
                        $params[4] = $this->_quoteOrderBy($params[4]);
                }
                // Compile the SELECT parameters
                list($select_fields, $from_table, $where_clause, $groupBy, $orderBy) = $this->compileSelectParameters($params);
+               $this->dbmsSpecifics->transformQueryParts($select_fields, $from_table, $where_clause, $groupBy, $orderBy);
                // Call parent method to build actual query
                $query = parent::SELECTquery($select_fields, $from_table, $where_clause, $groupBy, $orderBy);
                if ($this->debugOutput || $this->store_lastBuiltQuery) {
@@ -1229,17 +1312,17 @@ class DatabaseConnection extends \TYPO3\CMS\Core\Database\DatabaseConnection {
        protected function compileSelectParameters(array $params) {
                $select_fields = $this->SQLparser->compileFieldList($params[0]);
                $from_table = $this->SQLparser->compileFromTables($params[1]);
-               $where_clause = count($params[2]) > 0 ? $this->SQLparser->compileWhereClause($params[2]) : '';
-               $groupBy = count($params[3]) > 0 ? $this->SQLparser->compileFieldList($params[3]) : '';
-               $orderBy = count($params[4]) > 0 ? $this->SQLparser->compileFieldList($params[4]) : '';
+               $where_clause = !empty($params[2]) ? $this->SQLparser->compileWhereClause($params[2]) : '';
+               $groupBy = !empty($params[3]) ? $this->SQLparser->compileFieldList($params[3]) : '';
+               $orderBy = !empty($params[4]) ? $this->SQLparser->compileFieldList($params[4]) : '';
                return array($select_fields, $from_table, $where_clause, $groupBy, $orderBy);
        }
 
        /**
         * Creates a TRUNCATE TABLE SQL-statement
         *
-        * @param       string          See exec_TRUNCATEquery()
-        * @return      string          Full SQL query for TRUNCATE TABLE
+        * @param string $table See exec_TRUNCATEquery()
+        * @return string Full SQL query for TRUNCATE TABLE
         */
        public function TRUNCATEquery($table) {
                foreach ($this->preProcessHookObjects as $hookObject) {
@@ -1262,19 +1345,17 @@ class DatabaseConnection extends \TYPO3\CMS\Core\Database\DatabaseConnection {
        /**
         * Creates a SELECT prepared SQL statement.
         *
-        * @param string See exec_SELECTquery()
-        * @param string See exec_SELECTquery()
-        * @param string See exec_SELECTquery()
-        * @param string See exec_SELECTquery()
-        * @param string See exec_SELECTquery()
-        * @param string See exec_SELECTquery()
+        * @param string $select_fields See exec_SELECTquery()
+        * @param string $from_table See exec_SELECTquery()
+        * @param string $where_clause See exec_SELECTquery()
+        * @param string $groupBy See exec_SELECTquery()
+        * @param string $orderBy See exec_SELECTquery()
+        * @param string $limit See exec_SELECTquery()
         * @param array $input_parameters An array of values with as many elements as there are bound parameters in the SQL statement being executed. All values are treated as \TYPO3\CMS\Core\Database\PreparedStatement::PARAM_AUTOTYPE.
         * @return \TYPO3\CMS\Core\Database\PreparedStatement Prepared statement
         */
        public function prepare_SELECTquery($select_fields, $from_table, $where_clause, $groupBy = '', $orderBy = '', $limit = '', array $input_parameters = array()) {
-               if ($this->debug) {
-                       $pt = \TYPO3\CMS\Core\Utility\GeneralUtility::milliseconds();
-               }
+               $pt = $this->debug ? GeneralUtility::milliseconds() : 0;
                $precompiledParts = array();
                if ($this->queryCache) {
                        $cacheKey = 'prepare_SELECTquery-' . \TYPO3\CMS\Dbal\QueryCache::getCacheKey(array(
@@ -1292,11 +1373,12 @@ class DatabaseConnection extends \TYPO3\CMS\Core\Database\DatabaseConnection {
                                                'args' => array($from_table, $select_fields, $where_clause, $groupBy, $orderBy, $limit, $input_parameters),
                                                'precompiledParts' => $precompiledParts
                                        );
-                                       $this->debugHandler('prepare_SELECTquery (cache hit)', \TYPO3\CMS\Core\Utility\GeneralUtility::milliseconds() - $pt, $data);
+                                       $this->debugHandler('prepare_SELECTquery (cache hit)', GeneralUtility::milliseconds() - $pt, $data);
                                }
                        }
                }
-               if (count($precompiledParts) == 0) {
+               $ORIG_tableName = '';
+               if (empty($precompiledParts)) {
                        // Map table / field names if needed:
                        $ORIG_tableName = $from_table;
                        // Saving table names in $ORIG_from_table since $from_table is transformed beneath:
@@ -1329,12 +1411,12 @@ class DatabaseConnection extends \TYPO3\CMS\Core\Database\DatabaseConnection {
                                        $this->queryCache->set($cacheKey, $precompiledParts);
                                } catch (\TYPO3\CMS\Core\Cache\Exception $e) {
                                        if ($this->debug) {
-                                               \TYPO3\CMS\Core\Utility\GeneralUtility::devLog($e->getMessage(), 'dbal', 1);
+                                               GeneralUtility::devLog($e->getMessage(), 'dbal', 1);
                                        }
                                }
                        }
                }
-               $preparedStatement = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Database\\PreparedStatement', '', $from_table, $precompiledParts);
+               $preparedStatement = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Database\PreparedStatement::class, '', $from_table, $precompiledParts);
                /* @var $preparedStatement \TYPO3\CMS\Core\Database\PreparedStatement */
                // Bind values to parameters
                foreach ($input_parameters as $key => $value) {
@@ -1345,7 +1427,7 @@ class DatabaseConnection extends \TYPO3\CMS\Core\Database\DatabaseConnection {
                                'args' => array($from_table, $select_fields, $where_clause, $groupBy, $orderBy, $limit, $input_parameters),
                                'ORIG_from_table' => $ORIG_tableName
                        );
-                       $this->debugHandler('prepare_SELECTquery', \TYPO3\CMS\Core\Utility\GeneralUtility::milliseconds() - $pt, $data);
+                       $this->debugHandler('prepare_SELECTquery', GeneralUtility::milliseconds() - $pt, $data);
                }
                // Return prepared statement
                return $preparedStatement;
@@ -1360,6 +1442,7 @@ class DatabaseConnection extends \TYPO3\CMS\Core\Database\DatabaseConnection {
         * @param string $groupBy
         * @param string $orderBy
         * @param string $limit
+        * @throws \InvalidArgumentException
         * @return array
         */
        protected function getQueryComponents($select_fields, $from_table, $where_clause, $groupBy, $orderBy, $limit) {
@@ -1373,10 +1456,10 @@ class DatabaseConnection extends \TYPO3\CMS\Core\Database\DatabaseConnection {
                        'parameters' => array()
                );
                $this->lastHandlerKey = $this->handler_getFromTableList($from_table);
-               $hType = (string) $this->handlerCfg[$this->lastHandlerKey]['type'];
+               $hType = (string)$this->handlerCfg[$this->lastHandlerKey]['type'];
                if ($hType === 'adodb' && $this->runningADOdbDriver('postgres')) {
                        // Possibly rewrite the LIMIT to be PostgreSQL-compatible
-                       $splitLimit = \TYPO3\CMS\Core\Utility\GeneralUtility::intExplode(',', $limit);
+                       $splitLimit = GeneralUtility::intExplode(',', $limit);
                        // Splitting the limit values:
                        if ($splitLimit[1]) {
                                // If there are two parameters, do mapping differently than otherwise:
@@ -1426,115 +1509,86 @@ class DatabaseConnection extends \TYPO3\CMS\Core\Database\DatabaseConnection {
                $limit = $components['LIMIT'];
                $precompiledParts = array();
                $this->lastHandlerKey = $this->handler_getFromTableList($components['ORIG_tableName']);
-               $hType = (string) $this->handlerCfg[$this->lastHandlerKey]['type'];
+               $hType = (string)$this->handlerCfg[$this->lastHandlerKey]['type'];
                $precompiledParts['handler'] = $hType;
                $precompiledParts['ORIG_tableName'] = $components['ORIG_tableName'];
                switch ($hType) {
-               case 'native':
-                       if ($this->lastHandlerKey === '_DEFAULT' && !$this->isConnected()) {
-                               $this->connectDB();
-                       }
-                       $query = parent::SELECTquery($select_fields, $from_table, $where_clause, $groupBy, $orderBy, $limit);
-                       $precompiledParts['queryParts'] = explode($parameterWrap, $query);
-                       break;
-               case 'adodb':
-                       $query = parent::SELECTquery($select_fields, $from_table, $where_clause, $groupBy, $orderBy);
-                       $precompiledParts['queryParts'] = explode($parameterWrap, $query);
-                       $precompiledParts['LIMIT'] = $limit;
-                       break;
-               case 'userdefined':
-                       $precompiledParts['queryParts'] = array(
-                               'SELECT' => $select_fields,
-                               'FROM' => $from_table,
-                               'WHERE' => $where_clause,
-                               'GROUPBY' => $groupBy,
-                               'ORDERBY' => $orderBy,
-                               'LIMIT' => $limit
-                       );
-                       break;
+                       case 'native':
+                               $query = parent::SELECTquery($select_fields, $from_table, $where_clause, $groupBy, $orderBy, $limit);
+                               $precompiledParts['queryParts'] = explode($parameterWrap, $query);
+                               break;
+                       case 'adodb':
+                               $this->dbmsSpecifics->transformQueryParts($select_fields, $from_table, $where_clause, $groupBy, $orderBy, $limit);
+                               $query = parent::SELECTquery($select_fields, $from_table, $where_clause, $groupBy, $orderBy);
+                               $precompiledParts['queryParts'] = explode($parameterWrap, $query);
+                               $precompiledParts['LIMIT'] = $limit;
+                               break;
+                       case 'userdefined':
+                               $precompiledParts['queryParts'] = array(
+                                       'SELECT' => $select_fields,
+                                       'FROM' => $from_table,
+                                       'WHERE' => $where_clause,
+                                       'GROUPBY' => $groupBy,
+                                       'ORDERBY' => $orderBy,
+                                       'LIMIT' => $limit
+                               );
+                               break;
                }
                return $precompiledParts;
        }
 
        /**
-        * Executes a prepared query.
+        * Prepares a prepared query.
         *
         * @param string $query The query to execute
         * @param array $queryComponents The components of the query to execute
-        * @return pointer MySQL result pointer / DBAL object
-        * @access protected This method may only be called by \TYPO3\CMS\Core\Database\PreparedStatement
+        * @return bool|\mysqli_statement|\TYPO3\CMS\Dbal\Database\AdodbPreparedStatement
+        * @throws \RuntimeException
+        * @internal This method may only be called by \TYPO3\CMS\Core\Database\PreparedStatement
         */
-       public function exec_PREPAREDquery($query, array $precompiledParts) {
-               if ($this->debug) {
-                       $pt = \TYPO3\CMS\Core\Utility\GeneralUtility::milliseconds();
-               }
+       public function prepare_PREPAREDquery($query, array $queryComponents) {
+               $pt = $this->debug ? GeneralUtility::milliseconds() : 0;
                // Get handler key and select API:
-               switch ($precompiledParts['handler']) {
-               case 'native':
-                       $this->lastQuery = $query;
-                       $sqlResult = mysql_query($this->lastQuery, $this->handlerInstance[$this->lastHandlerKey]['link']);
-                       $this->resourceIdToTableNameMap[(string) $sqlResult] = $precompiledParts['ORIG_tableName'];
-                       break;
-               case 'adodb':
-                       $limit = $precompiledParts['LIMIT'];
-                       if ($this->runningADOdbDriver('postgres')) {
-                               // Possibly rewrite the LIMIT to be PostgreSQL-compatible
-                               $splitLimit = \TYPO3\CMS\Core\Utility\GeneralUtility::intExplode(',', $limit);
-                               // Splitting the limit values:
-                               if ($splitLimit[1]) {
-                                       // If there are two parameters, do mapping differently than otherwise:
-                                       $numrows = $splitLimit[1];
-                                       $offset = $splitLimit[0];
-                                       $limit = $numrows . ' OFFSET ' . $offset;
-                               }
-                       }
-                       if ($limit != '') {
-                               $splitLimit = \TYPO3\CMS\Core\Utility\GeneralUtility::intExplode(',', $limit);
-                               // Splitting the limit values:
-                               if ($splitLimit[1]) {
-                                       // If there are two parameters, do mapping differently than otherwise:
-                                       $numrows = $splitLimit[1];
-                                       $offset = $splitLimit[0];
-                               } else {
-                                       $numrows = $splitLimit[0];
-                                       $offset = 0;
-                               }
-                               $sqlResult = $this->handlerInstance[$this->lastHandlerKey]->SelectLimit($query, $numrows, $offset);
-                               $this->lastQuery = $sqlResult->sql;
-                       } else {
+               $preparedStatement = NULL;
+               switch ($queryComponents['handler']) {
+                       case 'native':
                                $this->lastQuery = $query;
-                               $sqlResult = $this->handlerInstance[$this->lastHandlerKey]->_Execute($this->lastQuery);
-                       }
-                       $sqlResult->TYPO3_DBAL_handlerType = 'adodb';
-                       // Setting handler type in result object (for later recognition!)
-                       $sqlResult->TYPO3_DBAL_tableList = $precompiledParts['ORIG_tableName'];
-                       break;
-               case 'userdefined':
-                       $queryParts = $precompiledParts['queryParts'];
-                       $sqlResult = $this->handlerInstance[$this->lastHandlerKey]->exec_SELECTquery($queryParts['SELECT'], $queryParts['FROM'], $queryParts['WHERE'], $queryParts['GROUPBY'], $queryParts['ORDERBY'], $queryParts['LIMIT']);
-                       if (is_object($sqlResult)) {
-                               $sqlResult->TYPO3_DBAL_handlerType = 'userdefined';
-                               // Setting handler type in result object (for later recognition!)
-                               $sqlResult->TYPO3_DBAL_tableList = $precompiledParts['ORIG_tableName'];
-                       }
-                       break;
+                               $preparedStatement = parent::prepare_PREPAREDquery($this->lastQuery, $queryComponents);
+                               $this->resourceIdToTableNameMap[serialize($preparedStatement)] = $queryComponents['ORIG_tableName'];
+                               break;
+                       case 'adodb':
+                               /** @var \TYPO3\CMS\Dbal\Database\AdodbPreparedStatement $preparedStatement */
+                               $preparedStatement = GeneralUtility::makeInstance(\TYPO3\CMS\Dbal\Database\AdodbPreparedStatement::class, $query, $queryComponents, $this);
+                               if (!$preparedStatement->prepare()) {
+                                       $preparedStatement = FALSE;
+                               }
+                               break;
+                       case 'userdefined':
+                               throw new \RuntimeException('prepare_PREPAREDquery is not implemented for userdefined handlers', 1394620167);
+                               /*
+                               $queryParts = $queryComponents['queryParts'];
+                               $preparedStatement = $this->handlerInstance[$this->lastHandlerKey]->exec_SELECTquery($queryParts['SELECT'], $queryParts['FROM'], $queryParts['WHERE'], $queryParts['GROUPBY'], $queryParts['ORDERBY'], $queryParts['LIMIT']);
+                               if (is_object($preparedStatement)) {
+                                       $preparedStatement->TYPO3_DBAL_handlerType = 'userdefined';
+                                       // Setting handler type in result object (for later recognition!)
+                                       $preparedStatement->TYPO3_DBAL_tableList = $queryComponents['ORIG_tableName'];
+                               }
+                               break;
+                               */
                }
                if ($this->printErrors && $this->sql_error()) {
                        debug(array($this->lastQuery, $this->sql_error()));
                }
                if ($this->debug) {
                        $data = array(
-                               'handlerType' => $precompiledParts['handler'],
-                               'args' => $precompiledParts,
-                               'ORIG_from_table' => $precompiledParts['ORIG_tableName']
+                               'handlerType' => $queryComponents['handler'],
+                               'args' => $queryComponents,
+                               'ORIG_from_table' => $queryComponents['ORIG_tableName']
                        );
-                       if ($this->conf['debugOptions']['numberRows']) {
-                               $data['numberRows'] = $this->sql_num_rows($sqlResult);
-                       }
-                       $this->debugHandler('exec_PREPAREDquery', \TYPO3\CMS\Core\Utility\GeneralUtility::milliseconds() - $pt, $data);
+                       $this->debugHandler('prepare_PREPAREDquery', GeneralUtility::milliseconds() - $pt, $data);
                }
                // Return result handler.
-               return $sqlResult;
+               return $preparedStatement;
        }
 
        /**************************************
@@ -1558,8 +1612,9 @@ class DatabaseConnection extends \TYPO3\CMS\Core\Database\DatabaseConnection {
        /**
         * Quotes field (and table) names with the quote character suitable for the DB being used
         *
-        * @param       string          List of fields to be used in query to DB
-        * @return      string          Quoted list of fields to be in query to DB
+        * @param string $select_fields List of fields to be used in query to DB
+        * @throws \InvalidArgumentException
+        * @return string Quoted list of fields to be in query to DB
         */
        public function quoteFieldNames($select_fields) {
                if ($select_fields == '') {
@@ -1577,7 +1632,7 @@ class DatabaseConnection extends \TYPO3\CMS\Core\Database\DatabaseConnection {
        }
 
        /**
-        * Quotes field (and table) names in a SQL SELECT clause acccording to DB rules
+        * Quotes field (and table) names in a SQL SELECT clause according to DB rules
         *
         * @param array $select_fields The parsed fields to quote
         * @return array
@@ -1616,11 +1671,11 @@ class DatabaseConnection extends \TYPO3\CMS\Core\Database\DatabaseConnection {
        /**
         * Quotes table names with the quote character suitable for the DB being used
         *
-        * @param       string          List of tables to be selected from DB
-        * @return      string          Quoted list of tables to be selected from DB
+        * @param string $from_table List of tables to be selected from DB
+        * @return string Quoted list of tables to be selected from DB
         */
        public function quoteFromTables($from_table) {
-               if ($from_table == '') {
+               if ($from_table === '') {
                        return '';
                }
                if ($this->runningNative()) {
@@ -1632,7 +1687,7 @@ class DatabaseConnection extends \TYPO3\CMS\Core\Database\DatabaseConnection {
        }
 
        /**
-        * Quotes table names in a SQL FROM clause acccording to DB rules
+        * Quotes table names in a SQL FROM clause according to DB rules
         *
         * @param array $from_table The parsed FROM clause to quote
         * @return array
@@ -1663,8 +1718,9 @@ class DatabaseConnection extends \TYPO3\CMS\Core\Database\DatabaseConnection {
        /**
         * Quotes the field (and table) names within a where clause with the quote character suitable for the DB being used
         *
-        * @param       string          A where clause that can be parsed by parseWhereClause
-        * @return      string          Usable where clause with quoted field/table names
+        * @param string $where_clause A where clause that can be parsed by parseWhereClause
+        * @throws \InvalidArgumentException
+        * @return string Usable where clause with quoted field/table names
         */
        public function quoteWhereClause($where_clause) {
                if ($where_clause === '' || $this->runningNative()) {
@@ -1681,10 +1737,10 @@ class DatabaseConnection extends \TYPO3\CMS\Core\Database\DatabaseConnection {
        }
 
        /**
-        * Quotes field names in a SQL WHERE clause acccording to DB rules
+        * Quotes field names in a SQL WHERE clause according to DB rules
         *
-        * @param       array           $where_clause The parsed WHERE clause to quote
-        * @return      array
+        * @param array $where_clause The parsed WHERE clause to quote
+        * @return array
         * @see quoteWhereClause()
         */
        protected function _quoteWhereClause(array $where_clause) {
@@ -1694,26 +1750,37 @@ class DatabaseConnection extends \TYPO3\CMS\Core\Database\DatabaseConnection {
                                $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 'FIND_IN_SET':
-                                       // quoteStr that will be used for Oracle
-                                       $pattern = str_replace($where_clause[$k]['func']['str'][1], '\\' . $where_clause[$k]['func']['str'][1], $where_clause[$k]['func']['str'][0]);
-                                       // table is not really needed and may in fact be empty in real statements
-                                       // but it's not overriden from \TYPO3\CMS\Core\Database\DatabaseConnection at the moment...
-                                       $patternForLike = $this->escapeStrForLike($pattern, $where_clause[$k]['func']['table']);
-                                       $where_clause[$k]['func']['str_like'] = $patternForLike;
-                               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;
+                                       case 'EXISTS':
+                                               $where_clause[$k]['func']['subquery'] = $this->quoteSELECTsubquery($v['func']['subquery']);
+                                               break;
+                                       case 'FIND_IN_SET':
+                                               // quoteStr that will be used for Oracle
+                                               $pattern = str_replace($where_clause[$k]['func']['str'][1], '\\' . $where_clause[$k]['func']['str'][1], $where_clause[$k]['func']['str'][0]);
+                                               // table is not really needed and may in fact be empty in real statements
+                                               // but it's not overridden from \TYPO3\CMS\Core\Database\DatabaseConnection at the moment...
+                                               $patternForLike = $this->escapeStrForLike($pattern, $where_clause[$k]['func']['table']);
+                                               $where_clause[$k]['func']['str_like'] = $patternForLike;
+                                               if ($where_clause[$k]['func']['table'] !== '') {
+                                                       $where_clause[$k]['func']['table'] = $this->quoteName($v['func']['table']);
+                                               }
+                                               if ($where_clause[$k]['func']['field'] !== '') {
+                                                       if ($this->dbmsSpecifics->getSpecific(Specifics\AbstractSpecifics::CAST_FIND_IN_SET)) {
+                                                               $where_clause[$k]['func']['field'] = 'CAST(' . $this->quoteName($v['func']['field']) . ' AS CHAR)';
+                                                       } else {
+                                                               $where_clause[$k]['func']['field'] = $this->quoteName($v['func']['field']);
+                                                       }
+                                               }
+                                               break;
+                                       case 'IFNULL':
+                                               // Intentional fallthrough
+                                       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'] != '') {
@@ -1739,15 +1806,18 @@ class DatabaseConnection extends \TYPO3\CMS\Core\Database\DatabaseConnection {
                                        }
                                } else {
                                        // Detecting value type; list or plain:
-                                       if (\TYPO3\CMS\Core\Utility\GeneralUtility::inList('NOTIN,IN', strtoupper(str_replace(array(' ', '
-', '
-', '   '), '', $where_clause[$k]['comparator'])))) {
+                                       if (GeneralUtility::inList('NOTIN,IN', strtoupper(str_replace(array(' ', LF, CR, TAB), '', $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], '.')) {
+                                               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]);
+                                               } elseif ($this->runningADOdbDriver('mssql')) {
+                                                       $where_clause[$k]['value'][0] = substr($this->handlerInstance[$this->lastHandlerKey]->qstr($where_clause[$k]['value'][0]), 1, -1);
                                                }
                                        }
                                }
@@ -1760,8 +1830,8 @@ class DatabaseConnection extends \TYPO3\CMS\Core\Database\DatabaseConnection {
         * Quotes the field (and table) names within a group by clause with the quote
         * character suitable for the DB being used
         *
-        * @param       string          A group by clause that can by parsed by parseFieldList
-        * @return      string          Usable group by clause with quoted field/table names
+        * @param string $groupBy A group by clause that can by parsed by parseFieldList
+        * @return string Usable group by clause with quoted field/table names
         */
        protected function quoteGroupBy($groupBy) {
                if ($groupBy === '') {
@@ -1776,10 +1846,10 @@ class DatabaseConnection extends \TYPO3\CMS\Core\Database\DatabaseConnection {
        }
 
        /**
-        * Quotes field names in a SQL GROUP BY clause acccording to DB rules
+        * Quotes field names in a SQL GROUP BY clause according to DB rules
         *
-        * @param       array           $groupBy The parsed GROUP BY clause to quote
-        * @return      array
+        * @param array $groupBy The parsed GROUP BY clause to quote
+        * @return array
         * @see quoteGroupBy()
         */
        protected function _quoteGroupBy(array $groupBy) {
@@ -1796,8 +1866,8 @@ class DatabaseConnection extends \TYPO3\CMS\Core\Database\DatabaseConnection {
         * Quotes the field (and table) names within an order by clause with the quote
         * character suitable for the DB being used
         *
-        * @param       string          An order by clause that can by parsed by parseFieldList
-        * @return      string          Usable order by clause with quoted field/table names
+        * @param string $orderBy An order by clause that can by parsed by parseFieldList
+        * @return string Usable order by clause with quoted field/table names
         */
        protected function quoteOrderBy($orderBy) {
                if ($orderBy === '') {
@@ -1812,9 +1882,9 @@ class DatabaseConnection extends \TYPO3\CMS\Core\Database\DatabaseConnection {
        }
 
        /**
-        * Quotes field names in a SQL ORDER BY clause acccording to DB rules
+        * Quotes field names in a SQL ORDER BY clause according to DB rules
         *
-        * @param       array           $orderBy The parsed ORDER BY clause to quote
+        * @param array $orderBy The parsed ORDER BY clause to quote
         * @return      array
         * @see quoteOrderBy()
         */
@@ -1839,58 +1909,66 @@ class DatabaseConnection extends \TYPO3\CMS\Core\Database\DatabaseConnection {
        /**
         * Escaping and quoting values for SQL statements.
         *
-        * @param       string          Input string
-        * @param       string          Table name for which to quote string. Just enter the table that the field-value is selected from (and any DBAL will look up which handler to use and then how to quote the string!).
-        * @return      string          Output string; Wrapped in single quotes and quotes in the string (" / ') and \ will be backslashed (or otherwise based on DBAL handler)
+        * @param string $str Input string
+        * @param string $table Table name for which to quote string. Just enter the table that the field-value is selected from (and any DBAL will look up which handler to use and then how to quote the string!).
+        * @param bool $allowNull Whether to allow NULL values
+        * @return string Output string; Wrapped in single quotes and quotes in the string (" / ') and \ will be backslashed (or otherwise based on DBAL handler)
         * @see quoteStr()
         */
-       public function fullQuoteStr($str, $table) {
+       public function fullQuoteStr($str, $table,  $allowNull = FALSE) {
+               if ($allowNull && $str === NULL) {
+                       return 'NULL';
+               }
                return '\'' . $this->quoteStr($str, $table) . '\'';
        }
 
        /**
         * Substitution for PHP function "addslashes()"
+        * Use this function instead of the PHP addslashes() function when you build queries - this will prepare your code for DBAL.
         * NOTICE: You must wrap the output of this function in SINGLE QUOTES to be DBAL compatible. Unless you have to apply the single quotes yourself you should rather use ->fullQuoteStr()!
         *
-        * @param       string          Input string
-        * @param       string          Table name for which to quote string. Just enter the table that the field-value is selected from (and any DBAL will look up which handler to use and then how to quote the string!).
-        * @return      string          Output string; Quotes (" / ') and \ will be backslashed (or otherwise based on DBAL handler)
+        * @param string $str Input string
+        * @param string $table Table name for which to quote string. Just enter the table that the field-value is selected from (and any DBAL will look up which handler to use and then how to quote the string!).
+        * @throws \RuntimeException
+        * @return string Output string; Quotes (" / ') and \ will be backslashed (or otherwise based on DBAL handler)
         * @see quoteStr()
         */
        public function quoteStr($str, $table) {
                $this->lastHandlerKey = $this->handler_getFromTableList($table);
-               switch ((string) $this->handlerCfg[$this->lastHandlerKey]['type']) {
-               case 'native':
-                       if ($this->handlerInstance[$this->lastHandlerKey]['link']) {
-                               if ($this->lastHandlerKey === '_DEFAULT' && !$this->isConnected()) {
+               switch ((string)$this->handlerCfg[$this->lastHandlerKey]['type']) {
+                       case 'native':
+                               if ($this->handlerInstance[$this->lastHandlerKey]['link']) {
+                                       if (!$this->isConnected()) {
+                                               $this->connectDB();
+                                       }
+                                       $str = $this->handlerInstance[$this->lastHandlerKey]['link']->real_escape_string($str);
+                               } else {
+                                       // link may be null when unit testing DBAL
+                                       $str = str_replace('\'', '\\\'', $str);
+                               }
+                               break;
+                       case 'adodb':
+                               if (!$this->isConnected()) {
                                        $this->connectDB();
                                }
-                               $str = mysql_real_escape_string($str, $this->handlerInstance[$this->lastHandlerKey]['link']);
-                       } else {
-                               // link may be null when unit testing DBAL
-                               $str = str_replace('\'', '\\\'', $str);
-                       }
-                       break;
-               case 'adodb':
-                       $str = substr($this->handlerInstance[$this->lastHandlerKey]->qstr($str), 1, -1);
-                       break;
-               case 'userdefined':
-                       $str = $this->handlerInstance[$this->lastHandlerKey]->quoteStr($str);
-                       break;
-               default:
-                       throw new \RuntimeException('No handler found!!!', 1310027655);
-                       break;
-               }
-               return $str;
-       }
+                               $str = substr($this->handlerInstance[$this->lastHandlerKey]->qstr($str), 1, -1);
+                               break;
+                       case 'userdefined':
+                               $str = $this->handlerInstance[$this->lastHandlerKey]->quoteStr($str);
+                               break;
+                       default:
+                               throw new \RuntimeException('No handler found!!!', 1310027655);
+               }
+               return $str;
+       }
 
        /**
         * Quotes an object name (table name, field, ...)
         *
-        * @param       string          Object's name
-        * @param       string          Handler key
-        * @param       boolean         If method NameQuote() is not used, whether to use backticks instead of driver-specific quotes
-        * @return      string          Properly-quoted object's name
+        * @param string $name Object's name
+        * @param string $handlerKey Handler key
+        * @param bool $useBackticks If method NameQuote() is not used, whether to use backticks instead of driver-specific quotes
+        * @return string Properly-quoted object's name
         */
        public function quoteName($name, $handlerKey = NULL, $useBackticks = FALSE) {
                $handlerKey = $handlerKey ? $handlerKey : $this->lastHandlerKey;
@@ -1910,29 +1988,48 @@ class DatabaseConnection extends \TYPO3\CMS\Core\Database\DatabaseConnection {
        /**
         * Return MetaType for native field type (ADOdb only!)
         *
-        * @param       string          native type as reported by admin_get_fields()
-        * @param       string          Table name for which query type string. Important for detection of DBMS handler of the query!
-        * @return      string          Meta type (currenly ADOdb syntax only, http://phplens.com/lens/adodb/docs-adodb.htm#metatype)
+        * @param string $type Native type as reported by admin_get_fields()
+        * @param string $table Table name for which query type string. Important for detection of DBMS handler of the query!
+        * @param int $maxLength
+        * @throws \RuntimeException
+        * @return string Meta type (currently ADOdb syntax only, http://phplens.com/lens/adodb/docs-adodb.htm#metatype)
+        * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8, use getMetadata() instead
         */
-       public function MetaType($type, $table, $max_length = -1) {
+       public function MetaType($type, $table, $maxLength = -1) {
+               GeneralUtility::logDeprecatedFunction();
+               return $this->getMetadata($type, $table, 'dummyFieldToBypassCache', $maxLength);
+       }
+
+       /**
+        * Return Metadata for native field type (ADOdb only!)
+        *
+        * @param string $type  Native type as reported by admin_get_fields()
+        * @param string $table Table name for which the type is queried. Important for detection of DBMS handler of the query!
+        * @param string $field Field name for which the type is queried. Important for accessing the field information cache.
+        * @param int    $maxLength
+        * @throws \RuntimeException
+        * @return string Meta type (currently ADOdb syntax only, http://phplens.com/lens/adodb/docs-adodb.htm#metatype)
+        */
+       public function getMetadata($type, $table, $field, $maxLength = -1) {
                $this->lastHandlerKey = $this->handler_getFromTableList($table);
                $str = '';
-               switch ((string) $this->handlerCfg[$this->lastHandlerKey]['type']) {
-               case 'native':
-                       $str = $type;
-                       break;
-               case 'adodb':
-                       if (in_array($table, $this->cache_fieldType)) {
-                               $rs = $this->handlerInstance[$this->lastHandlerKey]->SelectLimit('SELECT * FROM ' . $this->quoteFromTables($table), 1);
-                               $str = $rs->MetaType($type, $max_length);
-                       }
-                       break;
-               case 'userdefined':
-                       $str = $this->handlerInstance[$this->lastHandlerKey]->MetaType($str, $table, $max_length);
-                       break;
-               default:
-                       throw new \RuntimeException('No handler found!!!', 1310027685);
-                       break;
+               switch ((string)$this->handlerCfg[$this->lastHandlerKey]['type']) {
+                       case 'native':
+                               $str = $type;
+                               break;
+                       case 'adodb':
+                               if (!empty($this->cache_fieldType[$table][$field])) {
+                                       $str = $this->cache_fieldType[$table][$field]['metaType'];
+                               } else {
+                                       $rs = $this->handlerInstance[$this->lastHandlerKey]->SelectLimit('SELECT * FROM ' . $this->quoteFromTables($table), 1);
+                                       $str = $rs->MetaType($type, $maxLength);
+                               }
+                               break;
+                       case 'userdefined':
+                               $str = $this->handlerInstance[$this->lastHandlerKey]->MetaType($str, $table, $maxLength);
+                               break;
+                       default:
+                               throw new \RuntimeException('No handler found!!!', 1310027685);
                }
                return $str;
        }
@@ -1940,113 +2037,92 @@ class DatabaseConnection extends \TYPO3\CMS\Core\Database\DatabaseConnection {
        /**
         * Return MetaType for native MySQL field type
         *
-        * @param       string          native type as reported as in mysqldump files
-        * @return      string          Meta type (currenly ADOdb syntax only, http://phplens.com/lens/adodb/docs-adodb.htm#metatype)
+        * @param string $t native type as reported as in mysqldump files
+        * @return string Meta type (currently ADOdb syntax only, http://phplens.com/lens/adodb/docs-adodb.htm#metatype)
+        * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8
         */
        public function MySQLMetaType($t) {
-               switch (strtoupper($t)) {
-               case 'STRING':
-
-               case 'CHAR':
-
-               case 'VARCHAR':
-
-               case 'TINYBLOB':
-
-               case 'TINYTEXT':
-
-               case 'ENUM':
-
-               case 'SET':
-                       return 'C';
-               case 'TEXT':
-
-               case 'LONGTEXT':
-
-               case 'MEDIUMTEXT':
-                       return 'XL';
-               case 'IMAGE':
-
-               case 'LONGBLOB':
-
-               case 'BLOB':
-
-               case 'MEDIUMBLOB':
-                       return 'B';
-               case 'YEAR':
-
-               case 'DATE':
-                       return 'D';
-               case 'TIME':
-
-               case 'DATETIME':
-
-               case 'TIMESTAMP':
-                       return 'T';
-               case 'FLOAT':
-
-               case 'DOUBLE':
-                       return 'F';
-               case 'INT':
-
-               case 'INTEGER':
+               GeneralUtility::logDeprecatedFunction();
+               return $this->dbmsSpecifics->getMetaFieldType($t);
+       }
 
-               case 'TINYINT':
+       /**
+        * Return actual MySQL type for meta field type
+        *
+        * @param string $meta Meta type (currenly ADOdb syntax only, http://phplens.com/lens/adodb/docs-adodb.htm#metatype)
+        * @return string Native type as reported as in mysqldump files, uppercase
+        * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8
+        */
+       public function MySQLActualType($meta) {
+               GeneralUtility::logDeprecatedFunction();
+               return $this->dbmsSpecifics->getNativeFieldType($meta);
+       }
 
-               case 'SMALLINT':
+       /*********************************************
+        *
+        * SqlSchemaMigrationService helper functions
+        *
+        *********************************************/
+       /**
+        * Remove the index prefix length information from columns in an index definition.
+        * Partial indexes based on a prefix are not supported by all databases.
+        *
+        * @param string $indexSQL
+        * @return string
+        */
+       public function getEquivalentIndexDefinition($indexSQL) {
+               if ($this->dbmsSpecifics->specificExists(Specifics\AbstractSpecifics::PARTIAL_STRING_INDEX) && (bool)$this->dbmsSpecifics->getSpecific(Specifics\AbstractSpecifics::PARTIAL_STRING_INDEX)) {
+                       return $indexSQL;
+               }
 
-               case 'MEDIUMINT':
+               $strippedIndexSQL = preg_replace_callback(
+                       '/\A([^(]+)\((.*)\)\Z/',
+                       function($matches) {
+                               return $matches[1] . '(' . preg_replace('/\((\d+)\)/', '', $matches[2]) . ')';
+                       },
+                       $indexSQL
+               );
 
-               case 'BIGINT':
-                       return 'I8';
-               default:
-                       return 'N';
-               }
+               return $strippedIndexSQL === NULL ? $indexSQL : $strippedIndexSQL;
        }
 
        /**
-        * Return actual MySQL type for meta field type
+        * Convert the native MySQL Field type to the closest matching equivalent field type supported by the DBMS.
+        * INTEGER and TINYTEXT colums need to be further processed due to MySQL limitations / non-standard features.
         *
-        * @param       string          Meta type (currenly ADOdb syntax only, http://phplens.com/lens/adodb/docs-adodb.htm#metatype)
-        * @return      string          native type as reported as in mysqldump files, uppercase
+        * @param string $fieldSQL
+        * @return string
         */
-       public function MySQLActualType($meta) {
-               switch (strtoupper($meta)) {
-               case 'C':
-                       return 'VARCHAR';
-               case 'XL':
-
-               case 'X':
-                       return 'LONGTEXT';
-               case 'C2':
-                       return 'VARCHAR';
-               case 'X2':
-                       return 'LONGTEXT';
-               case 'B':
-                       return 'LONGBLOB';
-               case 'D':
-                       return 'DATE';
-               case 'T':
-                       return 'DATETIME';
-               case 'L':
-                       return 'TINYINT';
-               case 'I':
-
-               case 'I1':
-
-               case 'I2':
-
-               case 'I4':
-
-               case 'I8':
-                       return 'BIGINT';
-               case 'F':
-                       return 'DOUBLE';
-               case 'N':
-                       return 'NUMERIC';
-               default:
-                       return $meta;
+       public function getEquivalentFieldDefinition($fieldSQL) {
+               if (!preg_match('/^([a-z0-9]+)(\(([^\)]+)\))?(.*)/', $fieldSQL, $components)) {
+                       return $fieldSQL;
+               }
+
+               $metaType = $this->dbmsSpecifics->getMetaFieldType($components[1]);
+               $replacementType = $this->dbmsSpecifics->getNativeFieldType($metaType);
+               $replacementLength = $components[2];
+               $replacementExtra = '';
+
+               // MySQL INT types support a display length that has no effect on the
+               // actual range of values that can be stored, normalize to the default
+               // display length returned by DBAL.
+               if (substr($metaType, 0, 1) === 'I') {
+                       $replacementLength = $this->dbmsSpecifics->getNativeFieldLength($replacementType, $components[3]);
+               }
+
+               // MySQL TINYTEXT is equivalent to VARCHAR(255) DEFAULT NULL. MySQL TEXT
+               // columns can not have a default value in contrast to VARCHAR, so the
+               // `default NULL` gets appended to avoid false-positive schema changes.
+               if ($components[1] === 'tinytext') {
+                       $replacementLength = '(255)';
+                       if (FALSE !== stripos($components[0], ' NOT NULL')) {
+                               $replacementExtra = ' default \'\'';
+                       } else {
+                               $replacementExtra = ' default NULL';
+                       }
                }
+
+               return str_replace($components[1] . $components[2], strtolower($replacementType) . $replacementLength, $components[0]) . $replacementExtra;
        }
 
        /**************************************
@@ -2056,41 +2132,43 @@ class DatabaseConnection extends \TYPO3\CMS\Core\Database\DatabaseConnection {
         *
         **************************************/
        /**
-        * Returns the error status on the most recent sql() execution (based on $this->lastHandlerKey)
+        * Returns the error status on the last query() execution
         *
-        * @return      string          Handler error strings
+        * @return string MySQLi error string.
         */
        public function sql_error() {
+               $output = '';
                switch ($this->handlerCfg[$this->lastHandlerKey]['type']) {
-               case 'native':
-                       $output = mysql_error($this->handlerInstance[$this->lastHandlerKey]['link']);
-                       break;
-               case 'adodb':
-                       $output = $this->handlerInstance[$this->lastHandlerKey]->ErrorMsg();
-                       break;
-               case 'userdefined':
-                       $output = $this->handlerInstance[$this->lastHandlerKey]->sql_error();
-                       break;
+                       case 'native':
+                               $output = $this->handlerInstance[$this->lastHandlerKey]['link']->error;
+                               break;
+                       case 'adodb':
+                               $output = $this->handlerInstance[$this->lastHandlerKey]->ErrorMsg();
+                               break;
+                       case 'userdefined':
+                               $output = $this->handlerInstance[$this->lastHandlerKey]->sql_error();
+                               break;
                }
                return $output;
        }
 
        /**
-        * Returns the error number on the most recent sql() execution (based on $this->lastHandlerKey)
+        * Returns the error number on the last query() execution
         *
-        * @return      int             Handler error number
+        * @return int MySQLi error number
         */
        public function sql_errno() {
+               $output = 0;
                switch ($this->handlerCfg[$this->lastHandlerKey]['type']) {
-               case 'native':
-                       $output = mysql_errno($this->handlerInstance[$this->lastHandlerKey]['link']);
-                       break;
-               case 'adodb':
-                       $output = $this->handlerInstance[$this->lastHandlerKey]->ErrorNo();
-                       break;
-               case 'userdefined':
-                       $output = $this->handlerInstance[$this->lastHandlerKey]->sql_errno();
-                       break;
+                       case 'native':
+                               $output = $this->handlerInstance[$this->lastHandlerKey]['link']->errno;
+                               break;
+                       case 'adodb':
+                               $output = $this->handlerInstance[$this->lastHandlerKey]->ErrorNo();
+                               break;
+                       case 'userdefined':
+                               $output = $this->handlerInstance[$this->lastHandlerKey]->sql_errno();
+                               break;
                }
                return $output;
        }
@@ -2098,79 +2176,82 @@ class DatabaseConnection extends \TYPO3\CMS\Core\Database\DatabaseConnection {
        /**
         * Returns the number of selected rows.
         *
-        * @param       pointer         Result pointer / DBAL object
-        * @return      integer         Number of resulting rows.
+        * @param bool|\mysqli_result|object $res MySQLi result object / DBAL object
+        * @return int Number of resulting rows
         */
        public function sql_num_rows($res) {
                if ($res === FALSE) {
                        return FALSE;
                }
-               $handlerType = is_object($res) ? $res->TYPO3_DBAL_handlerType : 'native';
+               $handlerType = $this->determineHandlerType($res);
                $output = 0;
                switch ($handlerType) {
-               case 'native':
-                       $output = mysql_num_rows($res);
-                       break;
-               case 'adodb':
-                       $output = method_exists($res, 'RecordCount') ? $res->RecordCount() : 0;
-                       break;
-               case 'userdefined':
-                       $output = $res->sql_num_rows();
-                       break;
+                       case 'native':
+                               $output = $res->num_rows;
+                               break;
+                       case 'adodb':
+                               $output = method_exists($res, 'RecordCount') ? $res->RecordCount() : 0;
+                               break;
+                       case 'userdefined':
+                               $output = $res->sql_num_rows();
+                               break;
                }
                return $output;
        }
 
        /**
         * Returns an associative array that corresponds to the fetched row, or FALSE if there are no more rows.
+        * MySQLi fetch_assoc() wrapper function
         *
-        * @param       pointer         MySQL result pointer (of SELECT query) / DBAL object
-        * @return      array           Associative array of result row.
+        * @param bool|\mysqli_result|object $res MySQLi result object / DBAL object
+        * @return array|boolean Associative array of result row.
         */
        public function sql_fetch_assoc($res) {
+               $tableList = '';
                $output = FALSE;
-               $handlerType = is_object($res) ? $res->TYPO3_DBAL_handlerType : (is_resource($res) ? 'native' : FALSE);
-               switch ($handlerType) {
-               case 'native':
-                       $output = mysql_fetch_assoc($res);
-                       $tableList = $this->resourceIdToTableNameMap[(string) $res];
-                       // Reading list of tables from SELECT query:
-                       break;
-               case 'adodb':
-                       // Check if method exists for the current $res object.
-                       // If a table exists in TCA but not in the db, a error
-                       // occured because $res is not a valid object.
-                       if (method_exists($res, 'FetchRow')) {
-                               $output = $res->FetchRow();
-                               $tableList = $res->TYPO3_DBAL_tableList;
+               switch ($this->determineHandlerType($res)) {
+                       case 'native':
+                               $output = $res->fetch_assoc();
+                               $key = serialize($res);
+                               $tableList = $this->resourceIdToTableNameMap[$key];
+                               unset($this->resourceIdToTableNameMap[$key]);
                                // Reading list of tables from SELECT query:
-                               // Removing all numeric/integer keys.
-                               // A workaround because in ADOdb we would need to know what we want before executing the query...
-                               // MSSQL does not support ADODB_FETCH_BOTH and always returns an assoc. array instead. So
-                               // we don't need to remove anything.
-                               if (is_array($output)) {
-                                       if ($this->runningADOdbDriver('mssql')) {
-                                               // MSSQL does not know such thing as an empty string. So it returns one space instead, which we must fix.
-                                               foreach ($output as $key => $value) {
-                                                       if ($value === ' ') {
-                                                               $output[$key] = '';
+                               break;
+                       case 'adodb':
+                               // Check if method exists for the current $res object.
+                               // If a table exists in TCA but not in the db, an error
+                               // occurred because $res is not a valid object.
+                               if (method_exists($res, 'FetchRow')) {
+                                       $output = $res->FetchRow();
+                                       $tableList = $res->TYPO3_DBAL_tableList;
+                                       // Reading list of tables from SELECT query:
+                                       // Removing all numeric/integer keys.
+                                       // A workaround because in ADOdb we would need to know what we want before executing the query...
+                                       // MSSQL does not support ADODB_FETCH_BOTH and always returns an assoc. array instead. So
+                                       // we don't need to remove anything.
+                                       if (is_array($output)) {
+                                               if ($this->runningADOdbDriver('mssql')) {
+                                                       // MSSQL does not know such thing as an empty string. So it returns one space instead, which we must fix.
+                                                       foreach ($output as $key => $value) {
+                                                               if ($value === ' ') {
+                                                                       $output[$key] = '';
+                                                               }
                                                        }
-                                               }
-                                       } else {
-                                               foreach ($output as $key => $value) {
-                                                       if (is_integer($key)) {
-                                                               unset($output[$key]);
+                                               } else {
+                                                       foreach ($output as $key => $value) {
+                                                               if (is_integer($key)) {
+                                                                       unset($output[$key]);
+                                                               }
                                                        }
                                                }
                                        }
                                }
-                       }
-                       break;
-               case 'userdefined':
-                       $output = $res->sql_fetch_assoc();
-                       $tableList = $res->TYPO3_DBAL_tableList;
-                       // Reading list of tables from SELECT query:
-                       break;
+                               break;
+                       case 'userdefined':
+                               $output = $res->sql_fetch_assoc();
+                               $tableList = $res->TYPO3_DBAL_tableList;
+                               // Reading list of tables from SELECT query:
+                               break;
                }
                // Table/Fieldname mapping:
                if (is_array($output)) {
@@ -2178,6 +2259,10 @@ class DatabaseConnection extends \TYPO3\CMS\Core\Database\DatabaseConnection {
                                $output = $this->map_assocArray($output, $tables, 1);
                        }
                }
+               if ($output === NULL) {
+                       // Needed for compatibility
+                       $output = FALSE;
+               }
                // Return result:
                return $output;
        }
@@ -2185,99 +2270,124 @@ class DatabaseConnection extends \TYPO3\CMS\Core\Database\DatabaseConnection {
        /**
         * Returns an array that corresponds to the fetched row, or FALSE if there are no more rows.
         * The array contains the values in numerical indices.
+        * MySQLi fetch_row() wrapper function
         *
-        * @param       pointer         MySQL result pointer (of SELECT query) / DBAL object
-        * @return      array           Array with result rows.
+        * @param bool|\mysqli_result|object $res MySQLi result object / DBAL object
+        * @return array|boolean Array with result rows.
         */
        public function sql_fetch_row($res) {
                $output = FALSE;
-               $handlerType = is_object($res) ? $res->TYPO3_DBAL_handlerType : 'native';
-               switch ($handlerType) {
-               case 'native':
-                       $output = mysql_fetch_row($res);
-                       break;
-               case 'adodb':
-                       // Check if method exists for the current $res object.
-                       // If a table exists in TCA but not in the db, a error
-                       // occured because $res is not a valid object.
-                       if (method_exists($res, 'FetchRow')) {
-                               $output = $res->FetchRow();
-                               // Removing all assoc. keys.
-                               // A workaround because in ADOdb we would need to know what we want before executing the query...
-                               // MSSQL does not support ADODB_FETCH_BOTH and always returns an assoc. array instead. So
-                               // we need to convert resultset.
-                               if (is_array($output)) {
-                                       $keyIndex = 0;
-                                       foreach ($output as $key => $value) {
-                                               unset($output[$key]);
-                                               if (is_integer($key) || $this->runningADOdbDriver('mssql')) {
-                                                       $output[$keyIndex] = $value;
-                                                       if ($value === ' ') {
-                                                               // MSSQL does not know such thing as an empty string. So it returns one space instead, which we must fix.
-                                                               $output[$keyIndex] = '';
+               switch ($this->determineHandlerType($res)) {
+                       case 'native':
+                               $output = $res->fetch_row();
+                               if ($output === NULL) {
+                                       // Needed for compatibility
+                                       $output = FALSE;
+                               }
+                               break;
+                       case 'adodb':
+                               // Check if method exists for the current $res object.
+                               // If a table exists in TCA but not in the db, an error
+                               // occurred because $res is not a valid object.
+                               if (method_exists($res, 'FetchRow')) {
+                                       $output = $res->FetchRow();
+                                       // Removing all assoc. keys.
+                                       // A workaround because in ADOdb we would need to know what we want before executing the query...
+                                       // MSSQL does not support ADODB_FETCH_BOTH and always returns an assoc. array instead. So
+                                       // we need to convert resultset.
+                                       if (is_array($output)) {
+                                               $keyIndex = 0;
+                                               foreach ($output as $key => $value) {
+                                                       unset($output[$key]);
+                                                       if (is_integer($key) || $this->runningADOdbDriver('mssql')) {
+                                                               $output[$keyIndex] = $value;
+                                                               if ($value === ' ') {
+                                                                       // MSSQL does not know such thing as an empty string. So it returns one space instead, which we must fix.
+                                                                       $output[$keyIndex] = '';
+                                                               }
+                                                               $keyIndex++;
                                                        }
-                                                       $keyIndex++;
                                                }
                                        }
                                }
-                       }
-                       break;
-               case 'userdefined':
-                       $output = $res->sql_fetch_row();
-                       break;
+                               break;
+                       case 'userdefined':
+                               $output = $res->sql_fetch_row();
+                               break;
+               }
+               if ($output === NULL) {
+                       // Needed for compatibility
+                       $output = FALSE;
                }
                return $output;
        }
 
        /**
-        * Free result memory / unset result object
+        * Free result memory
+        * free_result() wrapper function
         *
-        * @param       pointer         MySQL result pointer to free / DBAL object
-        * @return      boolean         Returns TRUE on success or FALSE on failure.
+        * @param bool|\mysqli_result|object $res MySQLi result object / DBAL object
+        * @return bool Returns TRUE on success or FALSE on failure.
         */
        public function sql_free_result($res) {
                if ($res === FALSE) {
                        return FALSE;
                }
-               $handlerType = is_object($res) ? $res->TYPO3_DBAL_handlerType : 'native';
                $output = TRUE;
-               switch ($handlerType) {
-               case 'native':
-                       $output = mysql_free_result($res);
-                       break;
-               case 'adodb':
-                       if (method_exists($res, 'Close')) {
-                               $res->Close();
+               switch ($this->determineHandlerType($res)) {
+                       case 'native':
+                               $res->free();
+                               break;
+                       case 'adodb':
+                               if (method_exists($res, 'Close')) {
+                                       $res->Close();
+                                       unset($res);
+                                       $output = TRUE;
+                               } else {
+                                       $output = FALSE;
+                               }
+                               break;
+                       case 'userdefined':
                                unset($res);
-                               $output = TRUE;
-                       } else {
-                               $output = FALSE;
-                       }
-                       break;
-               case 'userdefined':
-                       unset($res);
-                       break;
+                               break;
                }
                return $output;
        }
 
        /**
+        * Determine handler type by result set
+        *
+        * @param bool|\mysqli_result|object $res MySQLi result set / DBAL Object
+        * @return bool|string
+        */
+       protected function determineHandlerType($res) {
+               if (is_object($res) && !$res instanceof \mysqli_result) {
+                       $handlerType = $res->TYPO3_DBAL_handlerType;
+               } elseif ($res instanceof \mysqli_result) {
+                       $handlerType = 'native';
+               } else {
+                       $handlerType = FALSE;
+               }
+               return $handlerType;
+       }
+
+       /**
         * Get the ID generated from the previous INSERT operation
         *
-        * @return      integer         The uid of the last inserted record.
+        * @return int The uid of the last inserted record.
         */
        public function sql_insert_id() {
                $output = 0;
                switch ($this->handlerCfg[$this->lastHandlerKey]['type']) {
-               case 'native':
-                       $output = mysql_insert_id($this->handlerInstance[$this->lastHandlerKey]['link']);
-                       break;
-               case 'adodb':
-                       $output = $this->handlerInstance[$this->lastHandlerKey]->last_insert_id;
-                       break;
-               case 'userdefined':
-                       $output = $this->handlerInstance[$this->lastHandlerKey]->sql_insert_id();
-                       break;
+                       case 'native':
+                               $output = $this->handlerInstance[$this->lastHandlerKey]['link']->insert_id;
+                               break;
+                       case 'adodb':
+                               $output = $this->handlerInstance[$this->lastHandlerKey]->last_insert_id;
+                               break;
+                       case 'userdefined':
+                               $output = $this->handlerInstance[$this->lastHandlerKey]->sql_insert_id();
+                               break;
                }
                return $output;
        }
@@ -2285,19 +2395,20 @@ class DatabaseConnection extends \TYPO3\CMS\Core\Database\DatabaseConnection {
        /**
         * Returns the number of rows affected by the last INSERT, UPDATE or DELETE query
         *
-        * @return      integer         Number of rows affected by last query
+        * @return int Number of rows affected by last query
         */
        public function sql_affected_rows() {
+               $output = 0;
                switch ($this->handlerCfg[$this->lastHandlerKey]['type']) {
-               case 'native':
-                       $output = mysql_affected_rows();
-                       break;
-               case 'adodb':
-                       $output = $this->handlerInstance[$this->lastHandlerKey]->Affected_Rows();
-                       break;
-               case 'userdefined':
-                       $output = $this->handlerInstance[$this->lastHandlerKey]->sql_affected_rows();
-                       break;
+                       case 'native':
+                               $output = $this->handlerInstance[$this->lastHandlerKey]['link']->affected_rows;
+                               break;
+                       case 'adodb':
+                               $output = $this->handlerInstance[$this->lastHandlerKey]->Affected_Rows();
+                               break;
+                       case 'userdefined':
+                               $output = $this->handlerInstance[$this->lastHandlerKey]->sql_affected_rows();
+                               break;
                }
                return $output;
        }
@@ -2305,23 +2416,22 @@ class DatabaseConnection extends \TYPO3\CMS\Core\Database\DatabaseConnection {
        /**
         * Move internal result pointer
         *
-        * @param       pointer         MySQL result pointer (of SELECT query) / DBAL object
-        * @param       integer         Seek result number.
-        * @return      boolean         Returns TRUE on success or FALSE on failure.
+        * @param bool|\mysqli_result|object $res MySQLi result object / DBAL object
+        * @param int $seek Seek result number.
+        * @return bool Returns TRUE on success or FALSE on failure.
         */
        public function sql_data_seek($res, $seek) {
                $output = TRUE;
-               $handlerType = is_object($res) ? $res->TYPO3_DBAL_handlerType : 'native';
-               switch ($handlerType) {
-               case 'native':
-                       $output = mysql_data_seek($res, $seek);
-                       break;
-               case 'adodb':
-                       $output = $res->Move($seek);
-                       break;
-               case 'userdefined':
-                       $output = $res->sql_data_seek($seek);
-                       break;
+               switch ($this->determineHandlerType($res)) {
+                       case 'native':
+                               $output = $res->data_seek($seek);
+                               break;
+                       case 'adodb':
+                               $output = $res->Move($seek);
+                               break;
+                       case 'userdefined':
+                               $output = $res->sql_data_seek($seek);
+                               break;
                }
                return $output;
        }
@@ -2331,17 +2441,13 @@ class DatabaseConnection extends \TYPO3\CMS\Core\Database\DatabaseConnection {
         *
         * If the first parameter is a string, it is used as table name for the lookup.
         *
-        * @param       pointer         MySQL result pointer (of SELECT query) / DBAL object / table name
-        * @param       integer         Field index. In case of ADOdb a string (field name!) FIXME
-        * @return      string          Returns the type of the specified field index
+        * @param string $table MySQL result pointer (of SELECT query) / DBAL object / table name
+        * @param int $field Field index. In case of ADOdb a string (field name!)
+        * @return string Returns the type of the specified field index
         */
        public function sql_field_metatype($table, $field) {
                // If $table and/or $field are mapped, use the original names instead
                foreach ($this->mapping as $tableName => $tableMapInfo) {
-                       if (isset($tableMapInfo['mapTableName']) && $tableMapInfo['mapTableName'] === $table) {
-                               // Table name is mapped => use original name
-                               $table = $tableName;
-                       }
                        if (isset($tableMapInfo['mapFieldNames'])) {
                                foreach ($tableMapInfo['mapFieldNames'] as $fieldName => $fieldMapInfo) {
                                        if ($fieldMapInfo === $field) {
@@ -2356,12 +2462,11 @@ class DatabaseConnection extends \TYPO3\CMS\Core\Database\DatabaseConnection {
 
        /**
         * Get the type of the specified field in a result
+        * mysql_field_type() wrapper function
         *
-        * If the first parameter is a string, it is used as table name for the lookup.
-        *
-        * @param       pointer         MySQL result pointer (of SELECT query) / DBAL object / table name
-        * @param       integer         Field index. In case of ADOdb a string (field name!) FIXME
-        * @return      string          Returns the type of the specified field index
+        * @param bool|\mysqli_result|object $res MySQLi result object / DBAL object
+        * @param int $pointer Field index.
+        * @return string Returns the name of the specified field index, or FALSE on error
         */
        public function sql_field_type($res, $pointer) {
                if ($res === NULL) {
@@ -2373,21 +2478,26 @@ class DatabaseConnection extends \TYPO3\CMS\Core\Database\DatabaseConnection {
                        }
                        $handlerType = 'adodb';
                } else {
-                       $handlerType = is_object($res) ? $res->TYPO3_DBAL_handlerType : 'native';
+                       $handlerType = $this->determineHandlerType($res);
                }
                $output = '';
                switch ($handlerType) {
-               case 'native':
-                       $output = mysql_field_type($res, $pointer);
-                       break;
-               case 'adodb':
-                       if (is_string($pointer)) {
-                               $output = $this->cache_fieldType[$res][$pointer]['type'];
-                       }
-                       break;
-               case 'userdefined':
-                       $output = $res->sql_field_type($pointer);
-                       break;
+                       case 'native':
+                               $metaInfo = $res->fetch_field_direct($pointer);
+                               if ($metaInfo) {
+                                       $output = $this->mysqlDataTypeMapping[$metaInfo->type];
+                               } else {
+                                       $output = '';
+                               }
+                               break;
+                       case 'adodb':
+                               if (is_string($pointer)) {
+                                       $output = $this->cache_fieldType[$res][$pointer]['type'];
+                               }
+                               break;
+                       case 'userdefined':
+                               $output = $res->sql_field_type($pointer);
+                               break;
                }
                return $output;
        }
@@ -2399,18 +2509,20 @@ class DatabaseConnection extends \TYPO3\CMS\Core\Database\DatabaseConnection {
         *
         **********/
        /**
-        * Executes a query
+        * Executes 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.
         *
         * 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.
+        * MySQLi query() wrapper function
+        * Beware: Use of this method should be avoided as it is experimentally supported by DBAL. You should consider
+        * using exec_SELECTquery() and similar methods instead.
         *
-        * @param       string          Query to execute
-        * @return      pointer         Result pointer / DBAL object
+        * @param string $query Query to execute
+        * @return bool|\mysqli_result|object MySQLi result object / DBAL object
         */
        public function sql_query($query) {
                $globalConfig = unserialize($GLOBALS['TYPO3_CONF_VARS']['EXT']['extConf']['dbal']);
@@ -2419,21 +2531,25 @@ class DatabaseConnection extends \TYPO3\CMS\Core\Database\DatabaseConnection {
                }
                // This method is heavily used by Extbase, try to handle it with DBAL-native methods
                $queryParts = $this->SQLparser->parseSQL($query);
-               if (is_array($queryParts) && \TYPO3\CMS\Core\Utility\GeneralUtility::inList('SELECT,UPDATE,INSERT,DELETE', $queryParts['type'])) {
+               if (is_array($queryParts) && GeneralUtility::inList('SELECT,UPDATE,INSERT,DELETE', $queryParts['type'])) {
                        return $this->exec_query($queryParts);
                }
+               $sqlResult = NULL;
                switch ($this->handlerCfg['_DEFAULT']['type']) {
-               case 'native':
-                       $sqlResult = mysql_query($query, $this->handlerInstance['_DEFAULT']['link']);
-                       break;
-               case 'adodb':
-                       $sqlResult = $this->handlerInstance['_DEFAULT']->Execute($query);
-                       $sqlResult->TYPO3_DBAL_handlerType = 'adodb';
-                       break;
-               case 'userdefined':
-                       $sqlResult = $this->handlerInstance['_DEFAULT']->sql_query($query);
-                       $sqlResult->TYPO3_DBAL_handlerType = 'userdefined';
-                       break;
+                       case 'native':
+                               if (!$this->isConnected()) {
+                                       $this->connectDB();
+                               }
+                               $sqlResult = $this->handlerInstance['_DEFAULT']['link']->query($query);
+                               break;
+                       case 'adodb':
+                               $sqlResult = $this->handlerInstance['_DEFAULT']->Execute($query);
+                               $sqlResult->TYPO3_DBAL_handlerType = 'adodb';
+                               break;
+                       case 'userdefined':
+                               $sqlResult = $this->handlerInstance['_DEFAULT']->sql_query($query);
+                               $sqlResult->TYPO3_DBAL_handlerType = 'userdefined';
+                               break;
                }
                $this->lastHandlerKey = '_DEFAULT';
                if ($this->printErrors && $this->sql_error()) {
@@ -2443,39 +2559,33 @@ class DatabaseConnection extends \TYPO3\CMS\Core\Database\DatabaseConnection {
        }
 
        /**
-        * Opening the _DEFAULT connection handler to the database.
-        * This is typically done by the scripts "init.php" in the backend or "index_ts.php" in the frontend (\TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController->connectToDB())
-        * You wouldn't need to use this at any time - let TYPO3 core handle this.
+        * Open a (persistent) connection to a MySQL server
         *
-        * @param string $host Deprecated since 6.1, will be removed in two versions. Database host IP/domain[:port]
-        * @param string $username Deprecated since 6.1, will be removed in two versions. Username to connect with.
-        * @param string $password Deprecated since 6.1, will be removed in two versions. Password to connect with.
-        * @return      mixed           Returns handler connection value
-        * @see handler_init()
+        * @return bool|void
         */
-       public function sql_pconnect($host = NULL, $username = NULL, $password = NULL) {
-               if ($host || $username || $password) {
-                       $this->handleDeprecatedConnectArguments($host, $username, $password);
-               }
-
-               // Overriding the _DEFAULT handler configuration of username, password, localhost and database name:
-               $this->handlerCfg['_DEFAULT']['config']['username'] = $this->databaseUsername;
-               $this->handlerCfg['_DEFAULT']['config']['password'] = $this->databaseUserPassword;
-               $this->handlerCfg['_DEFAULT']['config']['host'] = $this->databaseHost . ':' . $this->databasePort;
-               $this->handlerCfg['_DEFAULT']['config']['database'] = $this->databaseName;
-               // Initializing and output value:
-               $sqlResult = $this->handler_init('_DEFAULT');
-               return $sqlResult;
+       public function sql_pconnect() {
+               return $this->handler_init('_DEFAULT');
        }
 
        /**
-        * Select database for _DEFAULT handler.
+        * Select a SQL database
         *
-        * @param       string          Database to connect to.
-        * @return      boolean         Always returns TRUE; function is obsolete, database selection is made in handler_init() function!
+        * @return bool Returns TRUE on success or FALSE on failure.
         */
-       public function sql_select_db($TYPO3_db = '') {
-               return TRUE;
+       public function sql_select_db() {
+               $databaseName = $this->handlerCfg[$this->lastHandlerKey]['config']['database'];
+               $ret = TRUE;
+               if ((string)$this->handlerCfg[$this->lastHandlerKey]['type'] === 'native') {
+                       $ret = $this->handlerInstance[$this->lastHandlerKey]['link']->select_db($databaseName);
+               }
+               if (!$ret) {
+                       GeneralUtility::sysLog(
+                               'Could not select MySQL database ' . $databaseName . ': ' . $this->sql_error(),
+                               'core',
+                               GeneralUtility::SYSLOG_SEVERITY_FATAL
+                       );
+               }
+               return $ret;
        }
 
        /**************************************
@@ -2486,83 +2596,89 @@ class DatabaseConnection extends \TYPO3\CMS\Core\Database\DatabaseConnection {
         **************************************/
        /**
         * Listing databases from current MySQL connection. NOTICE: It WILL try to select those databases and thus break selection of current database.
+        * This is only used as a service function in the (1-2-3 process) of the Install Tool.
+        * In any case a lookup should be done in the _DEFAULT handler DBMS then.
         * Use in Install Tool only!
-        * Usage count/core: 1
         *
-        * @return      array           Each entry represents a database name
+        * @return array Each entry represents a database name
+        * @throws \RuntimeException
         */
        public function admin_get_dbs() {
                $dbArr = array();
+               $this->lastHandlerKey = '_DEFAULT';
                switch ($this->handlerCfg['_DEFAULT']['type']) {
-               case 'native':
-                       $db_list = mysql_list_dbs($this->link);
-                       while ($row = mysql_fetch_object($db_list)) {
-                               if ($this->sql_select_db($row->Database)) {
-                                       $dbArr[] = $row->Database;
+                       case 'native':
+                               /** @var \mysqli_result $db_list */
+                               $db_list = $this->query("SELECT SCHEMA_NAME FROM information_schema.SCHEMATA");
+                               $oldDb = $this->handlerCfg[$this->lastHandlerKey]['config']['database'];
+                               while ($row = $db_list->fetch_object()) {
+                                       $this->handlerCfg[$this->lastHandlerKey]['config']['database'] = $row->SCHEMA_NAME;
+                                       if ($this->sql_select_db()) {
+                                               $dbArr[] = $row->SCHEMA_NAME;
+                                       }
                                }
-                       }
-                       break;
-               case 'adodb':
-                       // check needed for install tool - otherwise it will just die because the call to
-                       // MetaDatabases is done on a stdClass instance
-                       if (method_exists($this->handlerInstance['_DEFAULT'], 'MetaDatabases')) {
-                               $sqlDBs = $this->handlerInstance['_DEFAULT']->MetaDatabases();
-                               if (is_array($sqlDBs)) {
-                                       foreach ($sqlDBs as $k => $theDB) {
-                                               $dbArr[] = $theDB;
+                               $this->handlerCfg[$this->lastHandlerKey]['config']['database'] = $oldDb;
+                               $db_list->free();
+                               break;
+                       case 'adodb':
+                               // check needed for install tool - otherwise it will just die because the call to
+                               // MetaDatabases is done on a stdClass instance
+                               if (method_exists($this->handlerInstance['_DEFAULT'], 'MetaDatabases')) {
+                                       $sqlDBs = $this->handlerInstance['_DEFAULT']->MetaDatabases();
+                                       if (is_array($sqlDBs)) {
+                                               foreach ($sqlDBs as $k => $theDB) {
+                                                       $dbArr[] = $theDB;
+                                               }
                                        }
                                }
-                       }
-                       break;
-               case 'userdefined':
-                       $dbArr = $this->handlerInstance['_DEFAULT']->admin_get_tables();
-                       break;
+                               break;
+                       case 'userdefined':
+                               $dbArr = $this->handlerInstance['_DEFAULT']->admin_get_tables();
+                               break;
                }
                return $dbArr;
        }
 
        /**
-        * Returns the list of tables from the system (quering the DBMSs)
-        * It looks up all tables from the DBMS of the _DEFAULT handler and then add all tables *configured* to be managed by other handlers
+        * Returns the list of tables from the default database, TYPO3_db (quering the DBMS)
+        * In a DBAL this method should 1) look up all tables from the DBMS  of
+        * the _DEFAULT handler and then 2) add all tables *configured* to be managed by other handlers
         *
-        * When fetching the tables, it skips tables whose names begin with BIN$, as this is taken as a table coming from the "Recycle Bin" on Oracle.
-        *
-        * @return      array           Tables in an array (tablename is in both key and value)
-        * @todo        Should the check for Oracle Recycle Bin stuff be moved elsewhere?
-        * @todo Should return table details in value! see \TYPO3\CMS\Core\Database\DatabaseConnection::admin_get_tables()
+        * @return array Array with tablenames as key and arrays with status information as value
         */
        public function admin_get_tables() {
                $whichTables = array();
                // Getting real list of tables:
                switch ($this->handlerCfg['_DEFAULT']['type']) {
-               case 'native':
-                       $tables_result = mysql_query('SHOW TABLE STATUS FROM `' . TYPO3_db . '`', $this->handlerInstance['_DEFAULT']['link']);
-                       if (!$this->sql_error()) {
-                               while ($theTable = $this->sql_fetch_assoc($tables_result)) {
-                                       $whichTables[$theTable['Name']] = $theTable;
+                       case 'native':
+                               $tables_result = $this->query('SHOW TABLE STATUS FROM `' . TYPO3_db . '`');
+                               if (!$this->sql_error()) {
+                                       while ($theTable = $this->sql_fetch_assoc($tables_result)) {
+                                               $whichTables[$theTable['Name']] = $theTable;
+                                       }
                                }
-                       }
-                       break;
-               case 'adodb':
-                       // check needed for install tool - otherwise it will just die because the call to
-                       // MetaTables is done on a stdClass instance
-                       if (method_exists($this->handlerInstance['_DEFAULT'], 'MetaTables')) {
-                               $sqlTables = $this->handlerInstance['_DEFAULT']->MetaTables('TABLES');
-                               foreach ($sqlTables as $k => $theTable) {
-                                       if (preg_match('/BIN\\$/', $theTable)) {
-                                               // Skip tables from the Oracle 10 Recycle Bin
-                                               continue;
+                               $tables_result->free();
+                               break;
+                       case 'adodb':
+                               // check needed for install tool - otherwise it will just die because the call to
+                               // MetaTables is done on a stdClass instance
+                               if (method_exists($this->handlerInstance['_DEFAULT'], 'MetaTables')) {
+                                       $sqlTables = $this->handlerInstance['_DEFAULT']->MetaTables('TABLES');
+                                       foreach ($sqlTables as $k => $theTable) {
+                                               if (preg_match('/BIN\\$/', $theTable)) {
+                                                       // Skip tables from the Oracle 10 Recycle Bin
+                                                       continue;
+                                               }
+                                               $whichTables[$theTable] = array('Name' => $theTable);
                                        }
-                                       $whichTables[$theTable] = $theTable;
                                }
-                       }
-                       break;
-               case 'userdefined':
-                       $whichTables = $this->handlerInstance['_DEFAULT']->admin_get_tables();
-                       break;
+                               break;
+                       case 'userdefined':
+                               $whichTables = $this->handlerInstance['_DEFAULT']->admin_get_tables();
+                               break;
                }
                // Check mapping:
-               if (is_array($this->mapping) && count($this->mapping)) {
+               if (is_array($this->mapping) && !empty($this->mapping)) {
                        // Mapping table names in reverse, first getting list of real table names:
                        $tMap = array();
                        foreach ($this->mapping as $tN => $tMapInfo) {
@@ -2575,6 +2691,7 @@ class DatabaseConnection extends \TYPO3\CMS\Core\Database\DatabaseConnection {
                        foreach ($whichTables as $tN => $tDefinition) {
                                if (isset($tMap[$tN])) {
                                        $tN = $tMap[$tN];
+                                       $tDefinition = array('Name' => $tN);
                                }
                                $newList[$tN] = $tDefinition;
                        }
@@ -2583,7 +2700,7 @@ class DatabaseConnection extends \TYPO3\CMS\Core\Database\DatabaseConnection {
                // Adding tables configured to reside in other DBMS (handler by other handlers than the default):
                if (is_array($this->table2handlerKeys)) {
                        foreach ($this->table2handlerKeys as $key => $handlerKey) {
-                               $whichTables[$key] = $key;
+                               $whichTables[$key] = array('Name' => $key);
                        }
                }
                return $whichTables;
@@ -2592,10 +2709,13 @@ class DatabaseConnection extends \TYPO3\CMS\Core\Database\DatabaseConnection {
        /**
         * Returns information about each field in the $table (quering the DBMS)
         * In a DBAL this should look up the right handler for the table and return compatible information
-        * This function is important not only for the Install Tool but probably for DBALs as well since they might need to look up table specific information in order to construct correct queries. In such cases this information should probably be cached for quick delivery
+        * This function is important not only for the Install Tool but probably for
+        * DBALs as well since they might need to look up table specific information
+        * in order to construct correct queries. In such cases this information should
+        * probably be cached for quick delivery.
         *
-        * @param       string          Table name
-        * @return      array           Field information in an associative array with fieldname => field row
+        * @param string $tableName Table name
+        * @return array Field information in an associative array with fieldname => field row
         */
        public function admin_get_fields($tableName) {
                $output = array();
@@ -2609,33 +2729,28 @@ class DatabaseConnection extends \TYPO3\CMS\Core\Database\DatabaseConnection {
                }
                // Find columns
                $this->lastHandlerKey = $this->handler_getFromTableList($tableName);
-               switch ((string) $this->handlerCfg[$this->lastHandlerKey]['type']) {
-               case 'native':
-                       $columns_res = mysql_query('SHOW columns FROM ' . $tableName, $this->handlerInstance[$this->lastHandlerKey]['link']);
-                       while ($fieldRow = mysql_fetch_assoc($columns_res)) {
-                               $output[$fieldRow['Field']] = $fieldRow;
-                       }
-                       break;
-               case 'adodb':
-                       $fieldRows = $this->handlerInstance[$this->lastHandlerKey]->MetaColumns($tableName, FALSE);
-                       if (is_array($fieldRows)) {
-                               foreach ($fieldRows as $k => $fieldRow) {
-                                       settype($fieldRow, 'array');
-                                       $fieldRow['Field'] = $fieldRow['name'];
-                                       $ntype = $this->MySQLActualType($this->MetaType($fieldRow['type'], $tableName));
-                                       $ntype .= $fieldRow['max_length'] != -1 ? ($ntype == 'INT' ? '(11)' : '(' . $fieldRow['max_length'] . ')') : '';
-                                       $fieldRow['Type'] = strtolower($ntype);
-                                       $fieldRow['Null'] = '';
-                                       $fieldRow['Key'] = '';
-                                       $fieldRow['Default'] = $fieldRow['default_value'];
-                                       $fieldRow['Extra'] = '';
-                                       $output[$fieldRow['name']] = $fieldRow;
-                               }
-                       }
-                       break;
-               case 'userdefined':
-                       $output = $this->handlerInstance[$this->lastHandlerKey]->admin_get_fields($tableName);
-                       break;
+               switch ((string)$this->handlerCfg[$this->lastHandlerKey]['type']) {
+                       case 'native':
+                               /** @var \mysqli_result $columns_res */
+                               $columns_res = $this->query('SHOW columns FROM ' . $tableName);
+                               while ($fieldRow = $columns_res->fetch_assoc()) {
+                                       $output[$fieldRow['Field']] = $fieldRow;
+                               }
+                               $columns_res->free();
+                               break;
+                       case 'adodb':
+                               $fieldRows = $this->handlerInstance[$this->lastHandlerKey]->MetaColumns($tableName, FALSE);
+                               if (is_array($fieldRows)) {
+                                       foreach ($fieldRows as $k => $fieldRow) {
+                                               settype($fieldRow, 'array');
+                                               $metaType = $this->getMetadata($fieldRow['type'], $tableName, $fieldRow['name']);
+                                               $output[$fieldRow['name']] = $this->dbmsSpecifics->transformFieldRowToMySQL($fieldRow, $metaType);
+                                       }
+                               }
+                               break;
+                       case 'userdefined':
+                               $output = $this->handlerInstance[$this->lastHandlerKey]->admin_get_fields($tableName);
+                               break;
                }
                // mapping should be done:
                if (is_array($tableArray) && is_array($this->mapping[$ORIG_tableName]['mapFieldNames'])) {
@@ -2657,8 +2772,8 @@ class DatabaseConnection extends \TYPO3\CMS\Core\Database\DatabaseConnection {
         * Returns information about each index key in the $table (quering the DBMS)
         * In a DBAL this should look up the right handler for the table and return compatible information
         *
-        * @param       string          Table name
-        * @return      array           Key information in a numeric array
+        * @param string $tableName Table name
+        * @return array Key information in a numeric array
         */
        public function admin_get_keys($tableName) {
                $output = array();
@@ -2672,62 +2787,64 @@ class DatabaseConnection extends \TYPO3\CMS\Core\Database\DatabaseConnection {
                }
                // Find columns
                $this->lastHandlerKey = $this->handler_getFromTableList($tableName);
-               switch ((string) $this->handlerCfg[$this->lastHandlerKey]['type']) {
-               case 'native':
-                       $keyRes = mysql_query('SHOW keys FROM ' . $tableName, $this->handlerInstance[$this->lastHandlerKey]['link']);
-                       while ($keyRow = mysql_fetch_assoc($keyRes)) {
-                               $output[] = $keyRow;
-                       }
-                       break;
-               case 'adodb':
-                       $keyRows = $this->handlerInstance[$this->lastHandlerKey]->MetaIndexes($tableName);
-                       if ($keyRows !== FALSE) {
-                               foreach ($keyRows as $k => $theKey) {
-                                       $theKey['Table'] = $tableName;
-                                       $theKey['Non_unique'] = (int) (!$theKey['unique']);
-                                       $theKey['Key_name'] = str_replace($tableName . '_', '', $k);
-                                       // the following are probably not needed anyway...
-                                       $theKey['Collation'] = '';
-                                       $theKey['Cardinality'] = '';
-                                       $theKey['Sub_part'] = '';
-                                       $theKey['Packed'] = '';
-                                       $theKey['Null'] = '';
-                                       $theKey['Index_type'] = '';
-                                       $theKey['Comment'] = '';
-                                       // now map multiple fields into multiple rows (we mimic MySQL, remember...)
-                                       $keycols = $theKey['columns'];
-                                       foreach ($keycols as $c => $theCol) {
+               switch ((string)$this->handlerCfg[$this->lastHandlerKey]['type']) {
+                       case 'native':
+                               /** @var \mysqli_result $keyRes */
+                               $keyRes = $this->query('SHOW keys FROM ' . $tableName);
+                               while ($keyRow = $keyRes->fetch_assoc()) {
+                                       $output[] = $keyRow;
+                               }
+                               $keyRes->free();
+                               break;
+                       case 'adodb':
+                               $keyRows = $this->handlerInstance[$this->lastHandlerKey]->MetaIndexes($tableName);
+                               if ($keyRows !== FALSE) {
+                                       foreach ($keyRows as $k => $theKey) {
+                                               $theKey['Table'] = $tableName;
+                                               $theKey['Non_unique'] = (int)(!$theKey['unique']);
+                                               $theKey['Key_name'] = str_replace(hash('crc32b', $tableName) . '_', '', $k);
+                                               // the following are probably not needed anyway...
+                                               $theKey['Collation'] = '';
+                                               $theKey['Cardinality'] = '';
+                                               $theKey['Sub_part'] = '';
+                                               $theKey['Packed'] = '';
+                                               $theKey['Null'] = '';
+                                               $theKey['Index_type'] = '';
+                                               $theKey['Comment'] = '';
+                                               // now map multiple fields into multiple rows (we mimic MySQL, remember...)
+                                               $keycols = $theKey['columns'];
+                                               foreach ($keycols as $c => $theCol) {
+                                                       $theKey['Seq_in_index'] = $c + 1;
+                                                       $theKey['Column_name'] = $theCol;
+                                                       $output[] = $theKey;
+                                               }
+                                       }
+                               }
+                               $priKeyRow = $this->handlerInstance[$this->lastHandlerKey]->MetaPrimaryKeys($tableName);
+                               $theKey = array();
+                               $theKey['Table'] = $tableName;
+                               $theKey['Non_unique'] = 0;
+                               $theKey['Key_name'] = 'PRIMARY';
+                               // the following are probably not needed anyway...
+                               $theKey['Collation'] = '';
+                               $theKey['Cardinality'] = '';
+                               $theKey['Sub_part'] = '';
+                               $theKey['Packed'] = '';
+                               $theKey['Null'] = '';
+                               $theKey['Index_type'] = '';
+                               $theKey['Comment'] = '';
+                               // now map multiple fields into multiple rows (we mimic MySQL, remember...)
+                               if ($priKeyRow !== FALSE) {
+                                       foreach ($priKeyRow as $c => $theCol) {
                                                $theKey['Seq_in_index'] = $c + 1;
                                                $theKey['Column_name'] = $theCol;
                                                $output[] = $theKey;
                                        }
                                }
-                       }
-                       $priKeyRow = $this->handlerInstance[$this->lastHandlerKey]->MetaPrimaryKeys($tableName);
-                       $theKey = array();
-                       $theKey['Table'] = $tableName;
-                       $theKey['Non_unique'] = 0;
-                       $theKey['Key_name'] = 'PRIMARY';
-                       // the following are probably not needed anyway...
-                       $theKey['Collation'] = '';
-                       $theKey['Cardinality'] = '';
-                       $theKey['Sub_part'] = '';
-                       $theKey['Packed'] = '';
-                       $theKey['Null'] = '';
-                       $theKey['Index_type'] = '';
-                       $theKey['Comment'] = '';
-                       // now map multiple fields into multiple rows (we mimic MySQL, remember...)
-                       if ($priKeyRow !== FALSE) {
-                               foreach ($priKeyRow as $c => $theCol) {
-                                       $theKey['Seq_in_index'] = $c + 1;
-                                       $theKey['Column_name'] = $theCol;
-                                       $output[] = $theKey;
-                               }
-                       }
-                       break;
-               case 'userdefined':
-                       $output = $this->handlerInstance[$this->lastHandlerKey]->admin_get_keys($tableName);
-                       break;
+                               break;
+                       case 'userdefined':
+                               $output = $this->handlerInstance[$this->lastHandlerKey]->admin_get_keys($tableName);
+                               break;
                }
                // mapping should be done:
                if (is_array($tableArray) && is_array($this->mapping[$ORIG_tableName]['mapFieldNames'])) {
@@ -2749,30 +2866,51 @@ class DatabaseConnection extends \TYPO3\CMS\Core\Database\DatabaseConnection {
        }
 
        /**
-        * mysql() wrapper function, used by the Install Tool.
+        * Returns information about the character sets supported by the current DBM
+        * This function is important not only for the Install Tool but probably for
+        * DBALs as well since they might need to look up table specific information
+        * in order to construct correct queries. In such cases this information should
+        * probably be cached for quick delivery.
         *
-        * @return      array
+        * This is used by the Install Tool to convert tables tables with non-UTF8 charsets
+        * Use in Install Tool only!
+        *
+        * @return array Array with Charset as key and an array of "Charset", "Description", "Default collation", "Maxlen" as values
         */
        public function admin_get_charsets() {
-               return array();
+               $output = array();
+               if ((string)$this->handlerCfg[$this->lastHandlerKey]['type'] === 'native') {
+                       /** @var \mysqli_result $columns_res */
+                       $columns_res = $this->query('SHOW CHARACTER SET');
+                       if ($columns_res !== FALSE) {
+                               while ($row = $columns_res->fetch_assoc()) {
+                                       $output[$row['Charset']] = $row;
+                               }
+                               $columns_res->free();
+                       }
+               }
+               return $output;
        }
 
        /**
-        * mysql() wrapper function, used by the Install Tool and EM for all queries regarding management of the database!
+        * mysqli() wrapper function, used by the Install Tool and EM for all queries regarding management of the database!
         *
-        * @param       string          Query to execute
-        * @return      pointer         Result pointer
+        * @param string $query Query to execute
+        * @throws \InvalidArgumentException
+        * @return bool|\mysqli_result|object MySQLi result object / DBAL object
         */
        public function admin_query($query) {
                $parsedQuery = $this->SQLparser->parseSQL($query);
+               if (!is_array($parsedQuery)) {
+                       throw new \InvalidArgumentException('ERROR: Query could not be parsed: "' . htmlspecialchars($parsedQuery) . '". Query: "' . htmlspecialchars($query) . '"', 1310027793);
+               }
                $ORIG_table = $parsedQuery['TABLE'];
-               if (is_array($parsedQuery)) {
-                       // Process query based on type:
-                       switch ($parsedQuery['type']) {
+               // Process query based on type:
+               switch ($parsedQuery['type']) {
                        case 'CREATETABLE':
-
                        case 'ALTERTABLE':
-
+                               $this->createMappingsIfRequired($parsedQuery);
+                               // Fall-through next instruction
                        case 'DROPTABLE':
                                $this->clearCachedFieldInfo();
                                $this->map_genericQueryParsed($parsedQuery);
@@ -2787,41 +2925,43 @@ class DatabaseConnection extends \TYPO3\CMS\Core\Database\DatabaseConnection {
                                break;
                        default:
                                throw new \InvalidArgumentException('ERROR: Invalid Query type (' . $parsedQuery['type'] . ') for ->admin_query() function!: "' . htmlspecialchars($query) . '"', 1310027740);
-                               break;
-                       }
-                       // Setting query array (for other applications to access if needed)
-                       $this->lastParsedAndMappedQueryArray = $parsedQuery;
-                       // Execute query (based on handler derived from the TABLE name which we actually know for once!)
-                       $this->lastHandlerKey = $this->handler_getFromTableList($ORIG_table);
-                       switch ((string) $this->handlerCfg[$this->lastHandlerKey]['type']) {
+               }
+               // Setting query array (for other applications to access if needed)
+               $this->lastParsedAndMappedQueryArray = $parsedQuery;
+               // Execute query (based on handler derived from the TABLE name which we actually know for once!)
+               $result = NULL;
+               $this->lastHandlerKey = $this->handler_getFromTableList($ORIG_table);
+               switch ((string)$this->handlerCfg[$this->lastHandlerKey]['type']) {
                        case 'native':
                                // Compiling query:
                                $compiledQuery = $this->SQLparser->compileSQL($this->lastParsedAndMappedQueryArray);
-                               if (in_array($this->lastParsedAndMappedQueryArray['type'], array('INSERT', 'DROPTABLE'))) {
-                                       return mysql_query($compiledQuery, $this->handlerInstance[$this->lastHandlerKey]['link']);
+                               if (in_array($this->lastParsedAndMappedQueryArray['type'], array('INSERT', 'DROPTABLE', 'ALTERTABLE'))) {
+                                       $result = $this->query($compiledQuery);
+                               } else {
+                                       $result = $this->query($compiledQuery[0]);
                                }
-                               return mysql_query($compiledQuery[0], $this->handlerInstance[$this->lastHandlerKey]['link']);
                                break;
                        case 'adodb':
                                // Compiling query:
                                $compiledQuery = $this->SQLparser->compileSQL($this->lastParsedAndMappedQueryArray);
                                switch ($this->lastParsedAndMappedQueryArray['type']) {
-                               case 'INSERT':
-                                       return $this->exec_INSERTquery($this->lastParsedAndMappedQueryArray['TABLE'], $compiledQuery);
-                               case 'TRUNCATETABLE':
-                                       return $this->exec_TRUNCATEquery($this->lastParsedAndMappedQueryArray['TABLE']);
+                                       case 'INSERT':
+                                               $result = $this->exec_INSERTquery($this->lastParsedAndMappedQueryArray['TABLE'], $compiledQuery);
+                                               break;
+                                       case 'TRUNCATETABLE':
+                                               $result = $this->exec_TRUNCATEquery($this->lastParsedAndMappedQueryArray['TABLE']);
+                                               break;
+                                       default:
+                                               $result = $this->handlerInstance[$this->lastHandlerKey]->DataDictionary->ExecuteSQLArray($compiledQuery);
                                }
-                               return $this->handlerInstance[$this->lastHandlerKey]->DataDictionary->ExecuteSQLArray($compiledQuery);
                                break;
                        case 'userdefined':
                                // Compiling query:
                                $compiledQuery = $this->SQLparser->compileSQL($this->lastParsedAndMappedQueryArray);
-                               return $this->handlerInstance[$this->lastHandlerKey]->admin_query($compiledQuery);
-                               break;
-                       }
-               } else {
-                       throw new \InvalidArgumentException('ERROR: Query could not be parsed: "' . htmlspecialchars($parsedQuery) . '". Query: "' . htmlspecialchars($query) . '"', 1310027793);
+                               $result = $this->handlerInstance[$this->lastHandlerKey]->admin_query($compiledQuery);
+                       default:
                }
+               return $result;
        }
 
        /************************************
@@ -2831,10 +2971,12 @@ class DatabaseConnection extends \TYPO3\CMS\Core\Database\DatabaseConnection {
         **************************************/
        /**
         * Return the handler key pointing to an appropriate database handler as found in $this->handlerCfg array
-        * Notice: TWO or more tables in the table list MUST use the SAME handler key - otherwise a fatal error is thrown! (Logically, no database can possibly join two tables from separate sources!)
+        * Notice: TWO or more tables in the table list MUST use the SAME handler key - otherwise a fatal error is thrown!
+        *         (Logically, no database can possibly join two tables from separate sources!)
         *
-        * @param       string          Table list, eg. "pages" or "pages, tt_content" or "pages AS A, tt_content AS B
-        * @return      string          Handler key (see $this->handlerCfg array) for table
+        * @param string $tableList Table list, eg. "pages" or "pages, tt_content" or "pages AS A, tt_content AS B
+        * @throws \RuntimeException
+        * @return string Handler key (see $this->handlerCfg array) for table
         */
        public function handler_getFromTableList($tableList) {
                $key = $tableList;
@@ -2843,7 +2985,7 @@ class DatabaseConnection extends \TYPO3\CMS\Core\Database\DatabaseConnection {
                        $_tableList = $tableList;
                        $tableArray = $this->SQLparser->parseFromTables($_tableList);
                        // If success, traverse the tables:
-                       if (is_array($tableArray) && count($tableArray)) {
+                       if (is_array($tableArray) && !empty($tableArray)) {
                                $outputHandlerKey = '';
                                foreach ($tableArray as $vArray) {
                                        // Find handler key, select "_DEFAULT" if none is specifically configured:
@@ -2870,48 +3012,77 @@ class DatabaseConnection extends \TYPO3\CMS\Core\Database\DatabaseConnection {
        /**
         * Initialize handler (connecting to database)
         *
-        * @param       string          Handler key
-        * @return      boolean         If connection went well, return TRUE
+        * @param string $handlerKey Handler key
+        * @return bool If connection went well, return TRUE
+        * @throws \RuntimeException
         * @see handler_getFromTableList()
         */
        public function handler_init($handlerKey) {
-               // Find handler configuration:
+               if (!isset($this->handlerCfg[$handlerKey]) || !is_array($this->handlerCfg[$handlerKey])) {
+                       throw new \RuntimeException('ERROR: No handler for key "' . $handlerKey . '"', 1310028018);
+               }
+               if ($handlerKey === '_DEFAULT') {
+                       // Overriding the _DEFAULT handler configuration of username, password, localhost and database name:
+                       $this->handlerCfg[$handlerKey]['config']['username'] = $this->databaseUsername;
+                       $this->handlerCfg[$handlerKey]['config']['password'] = $this->databaseUserPassword;
+                       $this->handlerCfg[$handlerKey]['config']['host'] = $this->databaseHost;
+                       $this->handlerCfg[$handlerKey]['config']['port'] = (int)$this->databasePort;
+                       $this->handlerCfg[$handlerKey]['config']['database'] = $this->databaseName;
+               }
                $cfgArray = $this->handlerCfg[$handlerKey];
-               $handlerType = (string) $cfgArray['type'];
+               if (!$cfgArray['config']['database']) {
+                       // Configuration is incomplete
+                       return FALSE;
+               }
+
                $output = FALSE;
-               if (is_array($cfgArray)) {
-                       if (!$cfgArray['config']['database']) {
-                               // Configuration is incomplete
-                               return;
-                       }
-                       switch ($handlerType) {
+               switch ((string)$cfgArray['type']) {
                        case 'native':
-                               if ($GLOBALS['TYPO3_CONF_VARS']['SYS']['no_pconnect']) {
-                                       $link = mysql_connect($cfgArray['config']['host'] . (isset($cfgArray['config']['port']) ? ':' . $cfgArray['config']['port'] : ''), $cfgArray['config']['username'], $cfgArray['config']['password'], TRUE);
-                               } else {
-                                       $link = mysql_pconnect($cfgArray['config']['host'] . (isset($cfgArray['config']['port']) ? ':' . $cfgArray['config']['port'] : ''), $cfgArray['config']['username'], $cfgArray['config']['password']);
-                               }
-                               // Set handler instance:
-                               $this->handlerInstance[$handlerKey] = array('handlerType' => 'native', 'link' => $link);
-                               // If link succeeded:
-                               if ($link) {
+                               $host = $cfgArray['config']['host'];
+                               if (!$GLOBALS['TYPO3_CONF_VARS']['SYS']['no_pconnect']) {
+                                       $host = 'p:' . $host;
+                               }
+                               $link = mysqli_init();
+                               $connected = $link->real_connect(
+                                       $host,
+                                       $cfgArray['config']['username'],
+                                       $cfgArray['config']['password'],
+                                       $cfgArray['config']['database'],
+                                       isset($cfgArray['config']['port']) ? $cfgArray['config']['port'] : ''
+                               );
+                               if ($connected) {
+                                       // Set handler instance:
+                                       $this->handlerInstance[$handlerKey] = array('handlerType' => 'native', 'link' => $link);
+
+                                       if ($link->set_charset($this->connectionCharset) === FALSE) {
+                                               GeneralUtility::sysLog(
+                                                       'Error setting connection charset to "' . $this->connectionCharset . '"',
+                                                       'core',
+                                                       GeneralUtility::SYSLOG_SEVERITY_ERROR
+                                               );
+                                       }
+
                                        // For default, set ->link (see \TYPO3\CMS\Core\Database\DatabaseConnection)
-                                       if ($handlerKey == '_DEFAULT') {
+                                       if ($handlerKey === '_DEFAULT') {
                                                $this->link = $link;
                                                $this->isConnected = TRUE;
-                                       }
-                                       // Select database as well:
-                                       if (mysql_select_db($cfgArray['config']['database'], $link)) {
-                                               $output = TRUE;
-                                       }
-                                       $setDBinit = \TYPO3\CMS\Core\Utility\GeneralUtility::trimExplode(LF, str_replace('\' . LF . \'', LF, $GLOBALS['TYPO3_CONF_VARS']['SYS']['setDBinit']), TRUE);
-                                       foreach ($setDBinit as $v) {
-                                               if (mysql_query($v, $link) === FALSE) {
-                                                       \TYPO3\CMS\Core\Utility\GeneralUtility::sysLog('Could not initialize DB connection with query "' . $v . '".', 'Core', 3);
+                                               $this->lastHandlerKey = $handlerKey;
+                                               foreach ($this->initializeCommandsAfterConnect as $command) {
+                                                       if ($this->query($command) === FALSE) {
+                                                               GeneralUtility::sysLog(
+                                                                       'Could not initialize DB connection with query "' . $command . '": ' . $this->sql_error(),
+                                                                       'core',
+                                                                       GeneralUtility::SYSLOG_SEVERITY_ERROR
+                                                               );
+                                                       }
                                                }
+                                               $this->setSqlMode();
+                                               $this->checkConnectionCharset();
                                        }
+
+                                       $output = TRUE;
                                } else {
-                                       \TYPO3\CMS\Core\Utility\GeneralUtility::sysLog('Could not connect to MySQL server ' . $cfgArray['config']['host'] . ' with user ' . $cfgArray['config']['username'] . '.', 'Core', 4);
+                                       GeneralUtility::sysLog('Could not connect to MySQL server ' . $cfgArray['config']['host'] . ' with user ' . $cfgArray['config']['username'] . '.', 'core', GeneralUtility::SYSLOG_SEVERITY_FATAL);
                                }
                                break;
                        case 'adodb':
@@ -2922,7 +3093,7 @@ class DatabaseConnection extends \TYPO3\CMS\Core\Database\DatabaseConnection {
                                }
                                $GLOBALS['ADODB_FORCE_TYPE'] = ADODB_FORCE_VALUE;
                                $GLOBALS['ADODB_FETCH_MODE'] = ADODB_FETCH_BOTH;
-                               $this->handlerInstance[$handlerKey] =& ADONewConnection($cfgArray['config']['driver']);
+                               $this->handlerInstance[$handlerKey] = ADONewConnection($cfgArray['config']['driver']);
                                // Set driver-specific options
                                if (isset($cfgArray['config']['driverOptions'])) {
                                        foreach ($cfgArray['config']['driverOptions'] as $optionName => $optionValue) {
@@ -2940,8 +3111,8 @@ class DatabaseConnection extends \TYPO3\CMS\Core\Database\DatabaseConnection {
                                        $this->handlerInstance[$handlerKey]->PConnect($cfgArray['config']['host'] . (isset($cfgArray['config']['port']) ? ':' . $cfgArray['config']['port'] : ''), $cfgArray['config']['username'], $cfgArray['config']['password'], $cfgArray['config']['database']);
                                }
                                if (!$this->handlerInstance[$handlerKey]->isConnected()) {
-                                       $dsn = $cfgArray['config']['driver'] . '://' . $cfgArray['config']['username'] . (strlen($cfgArray['config']['password']) ? ':XXXX@' : '') . $cfgArray['config']['host'] . (isset($cfgArray['config']['port']) ? ':' . $cfgArray['config']['port'] : '') . '/' . $cfgArray['config']['database'] . ($GLOBALS['TYPO3_CONF_VARS']['SYS']['no_pconnect'] ? '' : '?persistent=1');
-                                       \TYPO3\CMS\Core\Utility\GeneralUtility::sysLog('Could not connect to DB server using ADOdb on ' . $cfgArray['config']['host'] . ' with user ' . $cfgArray['config']['username'] . '.', 'Core', 4);
+                                       $dsn = $cfgArray['config']['driver'] . '://' . $cfgArray['config']['username'] . ((string)$cfgArray['config']['password'] !== '' ? ':XXXX@' : '') . $cfgArray['config']['host'] . (isset($cfgArray['config']['port']) ? ':' . $cfgArray['config']['port'] : '') . '/' . $cfgArray['config']['database'] . ($GLOBALS['TYPO3_CONF_VARS']['SYS']['no_pconnect'] ? '' : '?persistent=1');
+                                       GeneralUtility::sysLog('Could not connect to DB server using ADOdb on ' . $cfgArray['config']['host'] . ' with user ' . $cfgArray['config']['username'] . '.', 'core', GeneralUtility::SYSLOG_SEVERITY_FATAL);
                                        error_log('DBAL error: Connection to ' . $dsn . ' failed. Maybe PHP doesn\'t support the database?');
                                        $output = FALSE;
                                } else {
@@ -2955,15 +3126,19 @@ class DatabaseConnection extends \TYPO3\CMS\Core\Database\DatabaseConnection {
                                }
                                break;
                        case 'userdefined':
-                               // Find class file:
-                               $fileName = \TYPO3\CMS\Core\Utility\GeneralUtility::getFileAbsFileName($cfgArray['config']['classFile']);
-                               if (@is_file($fileName)) {
-                                       require_once $fileName;
-                               } else {
-                                       throw new \RuntimeException('DBAL error: "' . $fileName . '" was not a file to include.', 1310027975);
+                               // if not set class may also be loaded by autoload on demand
+                               if (isset($cfgArray['config']['classFile'])) {
+                                       GeneralUtility::deprecationLog('The DBAL handler option "config.classFile" is deprecated since TYPO3 CMS 7, and will be removed with CMS 8. Make use of autoloading instead.');
+                                       // Find class file:
+                                       $fileName = GeneralUtility::getFileAbsFileName($cfgArray['config']['classFile']);
+                                       if (@is_file($fileName)) {
+                                               require_once $fileName;
+                                       } else {
+                                               throw new \RuntimeException('DBAL error: "' . $fileName . '" was not a file to include.', 1310027975);
+                                       }
                                }
                                // Initialize:
-                               $this->handlerInstance[$handlerKey] = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance($cfgArray['config']['class']);
+                               $this->handlerInstance[$handlerKey] = GeneralUtility::makeInstance($cfgArray['config']['class']);
                                $this->handlerInstance[$handlerKey]->init($cfgArray, $this);
                                if (is_object($this->handlerInstance[$handlerKey])) {
                                        $output = TRUE;
@@ -2971,30 +3146,26 @@ class DatabaseConnection extends \TYPO3\CMS\Core\Database\DatabaseConnection {
                                break;
                        default:
                                throw new \RuntimeException('ERROR: Invalid handler type: "' . $cfgArray['type'] . '"', 1310027995);
-                               break;
-                       }
-                       return $output;
-               } else {
-                       throw new \RuntimeException('ERROR: No handler for key "' . $handlerKey . '"', 1310028018);
                }
+               return $output;
        }
 
        /**
         * Checks if database is connected.
         *
-        * @return boolean
+        * @return bool
         */
        public function isConnected() {
                $result = FALSE;
-               switch ((string) $this->handlerCfg[$this->lastHandlerKey]['type']) {
-               case 'native':
-                       $result = is_resource($this->link);
-                       break;
-               case 'adodb':
+               switch ((string)$this->handlerCfg[$this->lastHandlerKey]['type']) {
+                       case 'native':
+                               $result = isset($this->handlerCfg[$this->lastHandlerKey]['link']);
+                               break;
+                       case 'adodb':
 
-               case 'userdefined':
-                       $result = is_object($this->handlerInstance[$this->lastHandlerKey]) && $this->handlerInstance[$this->lastHandlerKey]->isConnected();
-                       break;
+                       case 'userdefined':
+                               $result = is_object($this->handlerInstance[$this->lastHandlerKey]) && $this->handlerInstance[$this->lastHandlerKey]->isConnected();
+                               break;
                }
                return $result;
        }
@@ -3002,20 +3173,42 @@ class DatabaseConnection extends \TYPO3\CMS\Core\Database\DatabaseConnection {
        /**
         * Checks whether the DBAL is currently inside an operation running on the "native" DB handler (i.e. MySQL)
         *
-        * @return boolean      True if running on "native" DB handler (i.e. MySQL)
+        * @return bool TRUE if running on "native" DB handler (i.e. MySQL)
         */
        public function runningNative() {
-               return (string) $this->handlerCfg[$this->lastHandlerKey]['type'] === 'native';
+               return (string)$this->handlerCfg[$this->lastHandlerKey]['type'] === 'native';
        }
 
        /**
         * Checks whether the ADOdb handler is running with a driver that contains the argument
         *
-        * @param string        $driver Driver name, matched with strstr().
-        * @return boolean      True if running with the given driver
+        * @param string $driver Driver name, matched with strstr().
+        * @return bool True if running with the given driver
         */
        public function runningADOdbDriver($driver) {
-               return strstr($this->handlerCfg[$this->lastHandlerKey]['config']['driver'], $driver);
+               return strpos($this->handlerCfg[$this->lastHandlerKey]['config']['driver'], $driver) !== FALSE;
+       }
+
+       /**
+        * Get the SQL server version
+        *
+        * @return string
+        */
+       public function getServerVersion() {
+               $result = '';
+               switch ((string)$this->handlerCfg[$this->lastHandlerKey]['type']) {
+                       case 'native':
+                               $result = $this->handlerInstance[$this->lastHandlerKey]['link']->server_info;
+                               break;
+                       case 'adodb':
+                       case 'userdefined':
+                               if (is_object($this->handlerInstance[$this->lastHandlerKey])) {
+                                       $serverInfo = $this->handlerInstance[$this->lastHandlerKey]->ServerInfo();
+                                       $result = $serverInfo['version'];
+                               }
+                               break;
+               }
+               return $result;
        }
 
        /************************************
@@ -3026,10 +3219,10 @@ class DatabaseConnection extends \TYPO3\CMS\Core\Database\DatabaseConnection {
        /**
         * Checks if mapping is needed for a table(list)
         *
-        * @param       string          List of tables in query
-        * @param       boolean         If TRUE, it will check only if FIELDs are configured and ignore the mapped table name if any.
-        * @param       array           Parsed list of tables, should be passed as reference to be reused and prevent double parsing
-        * @return      mixed           Returns an array of table names (parsed version of input table) if mapping is needed, otherwise just FALSE.
+        * @param string $tableList List of tables in query
+        * @param bool $fieldMappingOnly If TRUE, it will check only if FIELDs are configured and ignore the mapped table name if any.
+        * @param array $parsedTableList Parsed list of tables, should be passed as reference to be reused and prevent double parsing
+        * @return mixed Returns an array of table names (parsed version of input table) if mapping is needed, otherwise just FALSE.
         */
        protected function map_needMapping($tableList, $fieldMappingOnly = FALSE, array &$parsedTableList = array()) {
                $key = $tableList . '|' . $fieldMappingOnly;
@@ -3075,10 +3268,10 @@ class DatabaseConnection extends \TYPO3\CMS\Core\Database\DatabaseConnection {
         * Observe mapping problems with join-results (more than one table): Joined queries should always prefix the table name to avoid problems with this.
         * Observe that alias fields are not mapped of course (should not be a problem though)
         *
-        * @param       array           Input array, associative keys
-        * @param       array           Array of tables from the query. Normally just one table; many tables in case of a join. NOTICE: for multiple tables (with joins) there MIGHT occur trouble with fields of the same name in the two tables: This function traverses the mapping information for BOTH tables and applies mapping without checking from which table the field really came!
-        * @param       boolean         If TRUE, reverse direction. Default direction is to map an array going INTO the database (thus mapping TYPO3 fieldnames to PHYSICAL field names!)
-        * @return      array           Output array, with mapped associative keys.
+        * @param array $input Input array, associative keys
+        * @param array $tables Array of tables from the query. Normally just one table; many tables in case of a join. NOTICE: for multiple tables (with joins) there MIGHT occur trouble with fields of the same name in the two tables: This function traverses the mapping information for BOTH tables and applies mapping without checking from which table the field really came!
+        * @param bool $rev If TRUE, reverse direction. Default direction is to map an array going INTO the database (thus mapping TYPO3 fieldnames to PHYSICAL field names!)
+        * @return array Output array, with mapped associative keys.
         */
        protected function map_assocArray($input, $tables, $rev = FALSE) {
                // Traverse tables from query (hopefully only one table):
@@ -3114,12 +3307,12 @@ class DatabaseConnection extends \TYPO3\CMS\Core\Database\DatabaseConnection {
        /**
         * Remaps table/field names in a SELECT query's parts
         *
-        * @param       mixed           Either parsed list of tables (SQLparser->parseFromTables()) or list of fields to select from the table. This is what comes right after "SELECT ...". Required value.
-        * @param       string          Table(s) from which to select. This is what comes right after "FROM ...". Require value.
-        * @param       string          Where clause. This is what comes right after "WHERE ...". Can be blank.
-        * @param       string          Group by field(s)
-        * @param       string          Order by field(s)
-        * @return      void
+        * @param mixed $select_fields Either parsed list of tables (SQLparser->parseFromTables()) or list of fields to select from the table. This is what comes right after "SELECT ...". Required value.
+        * @param string $from_table Table(s) from which to select. This is what comes right after "FROM ...". Require value.
+        * @param string $where_clause Where clause. This is what comes right after "WHERE ...". Can be blank.
+        * @param string $groupBy Group by field(s)
+        * @param string $orderBy Order by field(s)
+        * @return array
         * @see exec_SELECTquery()
         */
        protected function map_remapSELECTQueryParts($select_fields, $from_table, $where_clause, $groupBy, $orderBy) {
@@ -3231,12 +3424,11 @@ class DatabaseConnection extends \TYPO3\CMS\Core\Database\DatabaseConnection {
        }
 
        /**
-        * Generic mapping of table/field names arrays (as parsed by \TYPO3\CMS\Core\Database\SqlParser)
+        * Generic mapping of table/field names arrays (as parsed by \TYPO3\CMS\Dbal\Database\SqlParser)
         *
-        * @param       array           Array with parsed SQL parts; Takes both fields, tables, where-parts, group and order-by. Passed by reference.
-        * @param       string          Default table name to assume if no table is found in $sqlPartArray
-        * @return      void
-        * @access private
+        * @param array $sqlPartArray Array with parsed SQL parts; Takes both fields, tables, where-parts, group and order-by. Passed by reference.
+        * @param string $defaultTable Default table name to assume if no table is found in $sqlPartArray
+        * @return void
         * @see map_remapSELECTQueryParts()
         */
        protected function map_sqlParts(&$sqlPartArray, $defaultTable) {
@@ -3246,36 +3438,37 @@ class DatabaseConnection extends \TYPO3\CMS\Core\Database\DatabaseConnection {
                        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[$defaultTableKey]['mapFieldNames']) && isset($this->mapping[$defaultTableKey]['mapFieldNames'][$fieldArray[0]])) {
-                                                               $sqlPartArray[$k]['case_field'] = $this->mapping[$defaultTableKey]['mapFieldNames'][$fieldArray[0]];
-                                                       } elseif (count($fieldArray) == 2) {
-                                                               // Map the external table
-                                                               $table = $fieldArray[0];
-                                                               $tableKey = $this->getMappingKey($table);
-                                                               if (isset($this->mapping[$tableKey]['mapTableName'])) {
-                                                                       $table = $this->mapping[$tableKey]['mapTableName'];
+                                               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']);
+                                                               $fieldArrayCount = count($fieldArray);
+                                                               if ($fieldArrayCount === 1 && is_array($this->mapping[$defaultTableKey]['mapFieldNames']) && isset($this->mapping[$defaultTableKey]['mapFieldNames'][$fieldArray[0]])) {
+                                                                       $sqlPartArray[$k]['case_field'] = $this->mapping[$defaultTableKey]['mapFieldNames'][$fieldArray[0]];
+                                                               } elseif ($fieldArrayCount === 2) {
+                                                                       // Map the external table
+                                                                       $table = $fieldArray[0];
+                                                                       $tableKey = $this->getMappingKey($table);
+                                                                       if (isset($this->mapping[$tableKey]['mapTableName'])) {
+                                                                               $table = $this->mapping[$tableKey]['mapTableName'];
+                                                                       }
+                                                                       // Map the field itself
+                                                                       $field = $fieldArray[1];
+                                                                       if (is_array($this->mapping[$tableKey]['mapFieldNames']) && isset($this->mapping[$tableKey]['mapFieldNames'][$fieldArray[1]])) {
+                                                                               $field = $this->mapping[$tableKey]['mapFieldNames'][$fieldArray[1]];
+                                                                       }
+                                                                       $sqlPartArray[$k]['case_field'] = $table . '.' . $field;
                                                                }
-                                                               // Map the field itself
-                                                               $field = $fieldArray[1];
-                                                               if (is_array($this->mapping[$tableKey]['mapFieldNames']) && isset($this->mapping[$tableKey]['mapFieldNames'][$fieldArray[1]])) {
-                                                                       $field = $this->mapping[$tableKey]['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;
+                                                       foreach ($sqlPartArray[$k]['when'] as $key => $when) {
+                                                               $this->map_sqlParts($sqlPartArray[$k]['when'][$key]['when_value'], $defaultTable);
+                                                       }
+                                                       break;
                                        }
                                }
                                // Look for sublevel (WHERE parts only)
@@ -3283,24 +3476,24 @@ class DatabaseConnection extends \TYPO3\CMS\Core\Database\DatabaseConnection {
                                        $this->map_sqlParts($sqlPartArray[$k]['sub'], $defaultTable);
                                } elseif (isset($sqlPartArray[$k]['func'])) {
                                        switch ($sqlPartArray[$k]['func']['type']) {
-                                       case 'EXISTS':
-                                               $this->map_subquery($sqlPartArray[$k]['func']['subquery']);
-                                               break;
-                                       case 'FIND_IN_SET':
-
-                                       case 'IFNULL':
-
-                                       case 'LOCATE':
-                                               // For the field, look for table mapping (generic):
-                                               $t = $sqlPartArray[$k]['func']['table'] ? $sqlPartArray[$k]['func']['table'] : $defaultTable;
-                                               $t = $this->getMappingKey($t);
-                                               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;
+                                               case 'EXISTS':
+                                                       $this->map_subquery($sqlPartArray[$k]['func']['subquery']);
+                                                       break;
+                                               case 'FIND_IN_SET':
+
+                                               case 'IFNULL':
+
+                                               case 'LOCATE':
+                                                       // For the field, look for table mapping (generic):
+                                                       $t = $sqlPartArray[$k]['func']['table'] ? $sqlPartArray[$k]['func']['table'] : $defaultTable;
+                                                       $t = $this->getMappingKey($t);
+                                                       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):
@@ -3313,10 +3506,11 @@ class DatabaseConnection extends \TYPO3\CMS\Core\Database\DatabaseConnection {
                                        // Mapping field name in SQL-functions like MIN(), MAX() or SUM()
                                        if ($this->mapping[$t]['mapFieldNames']) {
                                                $fieldArray = explode('.', $sqlPartArray[$k]['func_content']);
-                                               if (count($fieldArray) == 1 && is_array($this->mapping[$t]['mapFieldNames']) && isset($this->mapping[$t]['mapFieldNames'][$fieldArray[0]])) {
+                                               $fieldArrayCount = count($fieldArray);
+                                               if ($fieldArrayCount === 1 && is_array($this->mapping[$t]['mapFieldNames']) && isset($this->mapping[$t]['mapFieldNames'][$fieldArray[0]])) {
                                                        $sqlPartArray[$k]['func_content.'][0]['func_content'] = $this->mapping[$t]['mapFieldNames'][$fieldArray[0]];
                                                        $sqlPartArray[$k]['func_content'] = $this->mapping[$t]['mapFieldNames'][$fieldArray[0]];
-                                               } elseif (count($fieldArray) == 2) {
+                                               } elseif ($fieldArrayCount === 2) {
                                                        // Map the external table
                                                        $table = $fieldArray[0];
                                                        $tableKey = $this->getMappingKey($table);
@@ -3361,9 +3555,10 @@ class DatabaseConnection extends \TYPO3\CMS\Core\Database\DatabaseConnection {
                                        // this is a very simplistic check, beware
                                        if (!is_numeric($sqlPartArray[$k]['value'][0]) && !isset($sqlPartArray[$k]['value'][1])) {
                                                $fieldArray = explode('.', $sqlPartArray[$k]['value'][0]);
-                                               if (count($fieldArray) == 1 && is_array($this->mapping[$t]['mapFieldNames']) && isset($this->mapping[$t]['mapFieldNames'][$fieldArray[0]])) {
+                                               $fieldArrayCount = count($fieldArray);
+                                               if ($fieldArrayCount === 1 && is_array($this->mapping[$t]['mapFieldNames']) && isset($this->mapping[$t]['mapFieldNames'][$fieldArray[0]])) {
                                                        $sqlPartArray[$k]['value'][0] = $this->mapping[$t]['mapFieldNames'][$fieldArray[0]];
-                                               } elseif (count($fieldArray) == 2) {
+                                               } elseif ($fieldArrayCount === 2) {
                                                        // Map the external table
                                                        $table = $fieldArray[0];
                                                        $tableKey = $this->getMappingKey($table);
@@ -3424,25 +3619,28 @@ class DatabaseConnection extends \TYPO3\CMS\Core\Database\DatabaseConnection {
        }
 
        /**
-        * Will do table/field mapping on a general \TYPO3\CMS\Core\Database\SqlParser-compliant SQL query
+        * Will do table/field mapping on a general \TYPO3\CMS\Dbal\Database\SqlParser-compliant SQL query
         * (May still not support all query types...)
         *
-        * @param array Parsed QUERY as from \TYPO3\CMS\Core\Database\SqlParser::parseSQL(). NOTICE: Passed by reference!
-        * @return      void
+        * @param array $parsedQuery Parsed QUERY as from \TYPO3\CMS\Dbal\Database\SqlParser::parseSQL(). NOTICE: Passed by reference!
+        * @throws \InvalidArgumentException
+        * @return void
         * @see \TYPO3\CMS\Core\Database\SqlParser::parseSQL()
         */
        protected function map_genericQueryParsed(&$parsedQuery) {
                // Getting table - same for all:
                $table = $parsedQuery['TABLE'];
-               if ($table) {
-                       // Do field mapping if needed:
-                       if ($tableArray = $this->map_needMapping($table)) {
-                               // Table name:
-                               if ($this->mapping[$table]['mapTableName']) {
-                                       $parsedQuery['TABLE'] = $this->mapping[$table]['mapTableName'];
-                               }
-                               // Based on type, do additional changes:
-                               switch ($parsedQuery['type']) {
+               if (!$table) {
+                       throw new \InvalidArgumentException('ERROR, mapping: No table found in parsed Query array...', 1310028048);
+               }
+               // Do field mapping if needed:
+               if ($tableArray = $this->map_needMapping($table)) {
+                       // Table name:
+                       if ($this->mapping[$table]['mapTableName']) {
+                               $parsedQuery['TABLE'] = $this->mapping[$table]['mapTableName'];
+                       }
+                       // Based on type, do additional changes:
+                       switch ($parsedQuery['type']) {
                                case 'ALTERTABLE':
                                        // Changing field name:
                                        $newFieldName = $this->mapping[$table]['mapFieldNames'][$parsedQuery['FIELD']];
@@ -3477,19 +3675,16 @@ class DatabaseConnection extends \TYPO3\CMS\Core\Database\DatabaseConnection {
                                                }
                                        }
                                        break;
-                               }
                        }
-               } else {
-                       throw new \InvalidArgumentException('ERROR, mapping: No table found in parsed Query array...', 1310028048);
                }
        }
 
        /**
         * Re-mapping field names in array
         *
-        * @param       string          (TYPO3) Table name for fields.
-        * @param       array           Array of fieldnames to remap. Notice: Passed by reference!
-        * @return      void
+        * @param string $table (TYPO3) Table name for fields.
+        * @param array $fieldArray Array of fieldnames to remap. Notice: Passed by reference!
+        * @return void
         */
        protected function map_fieldNamesInArray($table, &$fieldArray) {
                if (is_array($this->mapping[$table]['mapFieldNames'])) {
@@ -3501,6 +3696,51 @@ class DatabaseConnection extends \TYPO3\CMS\Core\Database\DatabaseConnection {
                }
        }
 
+       /**
+        * Create a mapping for each table and field if required.
+        *
+        * @param array $parsedQuery The parsed query
+        * @return void
+        */
+       protected function createMappingsIfRequired($parsedQuery) {
+               if (
+                       !$this->dbmsSpecifics->specificExists(Specifics\AbstractSpecifics::TABLE_MAXLENGTH)
+                       && !$this->dbmsSpecifics->specificExists(Specifics\AbstractSpecifics::FIELD_MAXLENGTH)
+               ) {
+                       return;
+               }
+
+               $mappingConfiguration = array();
+               $table = $parsedQuery['TABLE'];
+               if (!isset($this->mapping[$table])) {
+                       $truncatedTable = $this->dbmsSpecifics->truncateIdentifier($table, Specifics\AbstractSpecifics::TABLE_MAXLENGTH);
+                       if ($table !== $truncatedTable) {
+                               $mappingConfiguration['mapTableName'] = $truncatedTable;
+                       }
+               }
+               foreach ($parsedQuery['FIELDS'] as $field => $_) {
+                       if (!isset($this->mapping[$table]['mapFieldNames'][$field])) {
+                               $truncatedField = $this->dbmsSpecifics->truncateIdentifier($field, Specifics\AbstractSpecifics::FIELD_MAXLENGTH);
+                               if ($field !== $truncatedField) {
+                                       $mappingConfiguration['mapFieldNames'][$field] = $truncatedField;
+                               }
+                       }
+               }
+               if (!empty($mappingConfiguration)) {
+                       /** @var \TYPO3\CMS\Extbase\Object\ObjectManager $objectManager */
+                       $objectManager = GeneralUtility::makeInstance(\TYPO3\CMS\Extbase\Object\ObjectManager::class);
+                       /** @var \TYPO3\CMS\Core\Configuration\ConfigurationManager $configurationManager */
+                       $configurationManager = $objectManager->get(\TYPO3\CMS\Core\Configuration\ConfigurationManager::class);
+                       $configurationManager->setLocalConfigurationValueByPath(
+                               'EXTCONF/dbal/mapping/' . $table,
+                               $mappingConfiguration
+                       );
+
+                       // renew mapping information
+                       $this->mapping = array_merge($this->mapping, array($table => $mappingConfiguration));
+               }
+       }
+
        /**************************************
         *
         * Debugging
@@ -3509,15 +3749,15 @@ class DatabaseConnection extends \TYPO3\CMS\Core\Database\DatabaseConnection {
        /**
         * Debug handler for query execution
         *
-        * @param       string          Function name from which this function is called.
-        * @param       string          Execution time in ms of the query
-        * @param       array           In-data of various kinds.
-        * @return      void
+        * @param string $function Function name from which this function is called.
+        * @param string $execTime Execution time in ms of the query
+        * @param array $inData In-data of various kinds.
+        * @return void
         * @access private
         */
        public function debugHandler($function, $execTime, $inData) {
                // we don't want to log our own log/debug SQL
-               $script = substr(PATH_thisScript, strlen(PATH_site));
+               $script = \TYPO3\CMS\Core\Utility\PathUtility::stripPathSitePrefix(PATH_thisScript);
                if (substr($script, -strlen('dbal/mod1/index.php')) != 'dbal/mod1/index.php' && !strstr($inData['args'][0], 'tx_dbal_debuglog')) {
                        $data = array();
                        $errorFlag = 0;
@@ -3534,16 +3774,16 @@ class DatabaseConnection extends \TYPO3\CMS\Core\Database\DatabaseConnection {
                        }
                        if ($this->conf['debugOptions']['numberRows']) {
                                switch ($function) {
-                               case 'exec_INSERTquery':
+                                       case 'exec_INSERTquery':
 
-                               case 'exec_UPDATEquery':
+                                       case 'exec_UPDATEquery':
 
-                               case 'exec_DELETEquery':
-                                       $data['numberRows'] = $this->sql_affected_rows();
-                                       break;
-                               case 'exec_SELECTquery':
-                                       $data['numberRows'] = $inData['numberRows'];
-                                       break;
+                                       case 'exec_DELETEquery':
+                                               $data['numberRows'] = $this->sql_affected_rows();
+                                               break;
+                                       case 'exec_SELECTquery':
+                                               $data['numberRows'] = $inData['numberRows'];
+                                               break;
                                }
                        }
                        if ($this->conf['debugOptions']['backtrace']) {
@@ -3553,50 +3793,50 @@ class DatabaseConnection extends \TYPO3\CMS\Core\Database\DatabaseConnection {
                                $data['backtrace'] = array_slice($backtrace, 0, $this->conf['debugOptions']['backtrace']);
                        }
                        switch ($function) {
-                       case 'exec_INSERTquery':
-
-                       case 'exec_UPDATEquery':
-
-                       case 'exec_DELETEquery':
-                               $this->debug_log($query, $execTime, $data, $joinTable, $errorFlag, $script);
-                               break;
-                       case 'exec_SELECTquery':
-                               // Get explain data:
-                               if ($this->conf['debugOptions']['EXPLAIN'] && \TYPO3\CMS\Core\Utility\GeneralUtility::inList('adodb,native', $inData['handlerType'])) {
-                                       $data['EXPLAIN'] = $this->debug_explain($this->lastQuery);
-                               }
-                               // Check parsing of Query:
-                               if ($this->conf['debugOptions']['parseQuery']) {
-                                       $parseResults = array();
-                                       $parseResults['SELECT'] = $this->SQLparser->debug_parseSQLpart('SELECT', $inData['args'][1]);
-                                       $parseResults['FROM'] = $this->SQLparser->debug_parseSQLpart('FROM', $inData['args'][0]);
-                                       $parseResults['WHERE'] = $this->SQLparser->debug_parseSQLpart('WHERE', $inData['args'][2]);
-                                       $parseResults['GROUPBY'] = $this->SQLparser->debug_parseSQLpart('SELECT', $inData['args'][3]);
-                                       // Using select field list syntax
-                                       $parseResults['ORDERBY'] = $this->SQLparser->debug_parseSQLpart('SELECT', $inData['args'][4]);
-                                       // Using select field list syntax
-                                       foreach ($parseResults as $k => $v) {
-                                               if (!strlen($parseResults[$k])) {
-                                                       unset($parseResults[$k]);
+                               case 'exec_INSERTquery':
+
+                               case 'exec_UPDATEquery':
+
+                               case 'exec_DELETEquery':
+                                       $this->debug_log($query, $execTime, $data, $joinTable, $errorFlag, $script);
+                                       break;
+                               case 'exec_SELECTquery':
+                                       // Get explain data:
+                                       if ($this->conf['debugOptions']['EXPLAIN'] && GeneralUtility::inList('adodb,native', $inData['handlerType'])) {
+                                               $data['EXPLAIN'] = $this->debug_explain($this->lastQuery);
+                                       }
+                                       // Check parsing of Query:
+                                       if ($this->conf['debugOptions']['parseQuery']) {
+                                               $parseResults = array();
+                                               $parseResults['SELECT'] = $this->SQLparser->debug_parseSQLpart('SELECT', $inData['args'][1]);
+                                               $parseResults['FROM'] = $this->SQLparser->debug_parseSQLpart('FROM', $inData['args'][0]);
+                                               $parseResults['WHERE'] = $this->SQLparser->debug_parseSQLpart('WHERE', $inData['args'][2]);
+                                               $parseResults['GROUPBY'] = $this->SQLparser->debug_parseSQLpart('SELECT', $inData['args'][3]);
+                                               // Using select field list syntax
+                                               $parseResults['ORDERBY'] = $this->SQLparser->debug_parseSQLpart('SELECT', $inData['args'][4]);
+                                               // Using select field list syntax
+                                               foreach ($parseResults as $k => $v) {
+                                                       if ($v === '') {
+                                                               unset($parseResults[$k]);
+                                                       }
+                                               }
+                                               if (!empty($parseResults)) {
+                                                       $data['parseError'] = $parseResults;
+                                                       $errorFlag |= 2;
                                                }
                                        }
-                                       if (count($parseResults)) {
-                                               $data['parseError'] = $parseResults;
-                                               $errorFlag |= 2;
+                                       // Checking joinTables:
+                                       if ($this->conf['debugOptions']['joinTables']) {
+                                               if (count(explode(',', $inData['ORIG_from_table'])) > 1) {
+                                                       $joinTable = $inData['args'][0];
+                                               }
                                        }
-                               }
-                               // Checking joinTables:
-                               if ($this->conf['debugOptions']['joinTables']) {
-                                       if (count(explode(',', $inData['ORIG_from_table'])) > 1) {
-                                               $joinTable = $inData['args'][0];
+                                       // Logging it:
+                                       $this->debug_log($query, $execTime, $data, $joinTable, $errorFlag, $script);
+                                       if (!empty($inData['args'][2])) {
+                                               $this->debug_WHERE($inData['args'][0], $inData['args'][2], $script);
                                        }
-                               }
-                               // Logging it:
-                               $this->debug_log($query, $execTime, $data, $joinTable, $errorFlag, $script);
-                               if (!empty($inData['args'][2])) {
-                                       $this->debug_WHERE($inData['args'][0], $inData['args'][2], $script);
-                               }
-                               break;
+                                       break;
                        }
                }
        }
@@ -3606,13 +3846,13 @@ class DatabaseConnection extends \TYPO3\CMS\Core\Database\DatabaseConnection {
         *
         * @param string $table Table name(s) the query was targeted at
         * @param string $where The WHERE clause to be logged
-        * @param string $script        The script calling the logging
+        * @param string $script The script calling the logging
         * @return void
         */
        public function debug_WHERE($table, $where, $script = '') {
                $insertArray = array(
                        'tstamp' => $GLOBALS['EXEC_TIME'],
-                       'beuser_id' => intval($GLOBALS['BE_USER']->user['uid']),
+                       'beuser_id' => (int)$GLOBALS['BE_USER']->user['uid'],
                        'script' => $script,
                        'tablename' => $table,
                        'whereclause' => $where
@@ -3623,21 +3863,21 @@ class DatabaseConnection extends \TYPO3\CMS\Core\Database\DatabaseConnection {
        /**
         * Inserts row in the log table
         *
-        * @param       string          The current query
-        * @param       integer         Execution time of query in milliseconds
-        * @param       array           Data to be stored serialized.
-        * @param       string          Join string if there IS a join.
-        * @param       integer         Error status.
-        * @param string $script        The script calling the logging
-        * @return      void
+        * @param string $query The current query
+        * @param int $ms Execution time of query in milliseconds
+        * @param array $data Data to be stored serialized.
+        * @param string $join Join string if there IS a join.
+        * @param int $errorFlag Error status.
+        * @param string $script The script calling the logging
+        * @return void
         */
        public function debug_log($query, $ms, $data, $join, $errorFlag, $script = '') {
                if (is_array($query)) {
                        $queryToLog = $query[0] . ' --  ';
-                       if (count($query[1])) {
+                       if (!empty($query[1])) {
                                $queryToLog .= count($query[1]) . ' BLOB FIELDS: ' . implode(', ', array_keys($query[1]));
                        }
-                       if (count($query[2])) {
+                       if (!empty($query[2])) {
                                $queryToLog .= count($query[2]) . ' CLOB FIELDS: ' . implode(', ', array_keys($query[2]));
                        }
                } else {
@@ -3645,7 +3885,7 @@ class DatabaseConnection extends \TYPO3\CMS\Core\Database\DatabaseConnection {
                }
                $insertArray = array(
                        'tstamp' => $GLOBALS['EXEC_TIME'],
-            &