[!!!][TASK] Doctrine: Remove ext:dbal 34/49734/4
authorMorton Jonuschat <m.jonuschat@mojocode.de>
Thu, 1 Sep 2016 20:44:41 +0000 (22:44 +0200)
committerMorton Jonuschat <m.jonuschat@mojocode.de>
Thu, 1 Sep 2016 21:36:57 +0000 (23:36 +0200)
Remove extension dbal from core and add an upgrade wizard
to fetch both ext:dbal and ext:adodb from TER.

Change-Id: I5a0c6dda4ac6c40e886cf78717991b457f074833
Resolves: #77762
Releases: master
Reviewed-on: https://review.typo3.org/49734
Tested-by: Bamboo TYPO3com <info@typo3.com>
Tested-by: Christian Kuhn <lolli@schwarzbu.ch>
Reviewed-by: Christian Kuhn <lolli@schwarzbu.ch>
Reviewed-by: Wouter Wolters <typo3@wouterwolters.nl>
Tested-by: Wouter Wolters <typo3@wouterwolters.nl>
Reviewed-by: Morton Jonuschat <m.jonuschat@mojocode.de>
Tested-by: Morton Jonuschat <m.jonuschat@mojocode.de>
97 files changed:
composer.json
composer.lock
typo3/sysext/core/Documentation/Changelog/master/Breaking-77762-ExtensionsDbalAndAdodbMovedToTER.rst [new file with mode: 0644]
typo3/sysext/dbal/Classes/Controller/ModuleController.php [deleted file]
typo3/sysext/dbal/Classes/Database/AdodbPreparedStatement.php [deleted file]
typo3/sysext/dbal/Classes/Database/DatabaseConnection.php [deleted file]
typo3/sysext/dbal/Classes/Database/Specifics/AbstractSpecifics.php [deleted file]
typo3/sysext/dbal/Classes/Database/Specifics/NullSpecifics.php [deleted file]
typo3/sysext/dbal/Classes/Database/Specifics/Oci8Specifics.php [deleted file]
typo3/sysext/dbal/Classes/Database/Specifics/PostgresSpecifics.php [deleted file]
typo3/sysext/dbal/Classes/Database/SqlCompilers/AbstractCompiler.php [deleted file]
typo3/sysext/dbal/Classes/Database/SqlCompilers/Adodb.php [deleted file]
typo3/sysext/dbal/Classes/Database/SqlCompilers/Mysql.php [deleted file]
typo3/sysext/dbal/Classes/Database/SqlParser.php [deleted file]
typo3/sysext/dbal/Classes/ExtensionManager/MessageDisplay.php [deleted file]
typo3/sysext/dbal/Classes/QueryCache.php [deleted file]
typo3/sysext/dbal/Classes/Report/DbalStatus.php [deleted file]
typo3/sysext/dbal/Classes/Service/SqlSchemaMigrationService.php [deleted file]
typo3/sysext/dbal/Documentation/.gitignore [deleted file]
typo3/sysext/dbal/Documentation/Appendices/Index.rst [deleted file]
typo3/sysext/dbal/Documentation/Appendices/UsingOracleWithTypo3/ConfiguringDatabaseAccess/Index.rst [deleted file]
typo3/sysext/dbal/Documentation/Appendices/UsingOracleWithTypo3/Index.rst [deleted file]
typo3/sysext/dbal/Documentation/Appendices/UsingOracleWithTypo3/InstallingAndConfiguringAdodbAndDbal/Index.rst [deleted file]
typo3/sysext/dbal/Documentation/Appendices/UsingPostgresqlWithTypo3/CompatibilityTuning/Index.rst [deleted file]
typo3/sysext/dbal/Documentation/Appendices/UsingPostgresqlWithTypo3/ConfiguringDatabaseAccess/Index.rst [deleted file]
typo3/sysext/dbal/Documentation/Appendices/UsingPostgresqlWithTypo3/Index.rst [deleted file]
typo3/sysext/dbal/Documentation/Appendices/UsingPostgresqlWithTypo3/InstallingAndConfiguringAdodbAndDbal/Index.rst [deleted file]
typo3/sysext/dbal/Documentation/Bugs/Index.rst [deleted file]
typo3/sysext/dbal/Documentation/Configuration/ConfigurationHints/Index.rst [deleted file]
typo3/sysext/dbal/Documentation/Configuration/Debug/Index.rst [deleted file]
typo3/sysext/dbal/Documentation/Configuration/Handlercfg/Index.rst [deleted file]
typo3/sysext/dbal/Documentation/Configuration/Index.rst [deleted file]
typo3/sysext/dbal/Documentation/Configuration/Introduction/Index.rst [deleted file]
typo3/sysext/dbal/Documentation/Configuration/Mapping/Index.rst [deleted file]
typo3/sysext/dbal/Documentation/Configuration/Memcached/Index.rst [deleted file]
typo3/sysext/dbal/Documentation/Configuration/Typo3ConfVars/Index.rst [deleted file]
typo3/sysext/dbal/Documentation/DebugBackendModule/Configuration/Index.rst [deleted file]
typo3/sysext/dbal/Documentation/DebugBackendModule/DatabaseInformation/Index.rst [deleted file]
typo3/sysext/dbal/Documentation/DebugBackendModule/DebugLog/Index.rst [deleted file]
typo3/sysext/dbal/Documentation/DebugBackendModule/Index.rst [deleted file]
typo3/sysext/dbal/Documentation/DebugBackendModule/SqlCheck/Index.rst [deleted file]
typo3/sysext/dbal/Documentation/Extensions/CodingGuidelines/Index.rst [deleted file]
typo3/sysext/dbal/Documentation/Extensions/Index.rst [deleted file]
typo3/sysext/dbal/Documentation/Extensions/Introduction/Index.rst [deleted file]
typo3/sysext/dbal/Documentation/Extensions/SmallCookbook/Index.rst [deleted file]
typo3/sysext/dbal/Documentation/Extensions/SqlStandard/Index.rst [deleted file]
typo3/sysext/dbal/Documentation/Faq/Index.rst [deleted file]
typo3/sysext/dbal/Documentation/Images/DebugLog.png [deleted file]
typo3/sysext/dbal/Documentation/Includes.txt [deleted file]
typo3/sysext/dbal/Documentation/Index.rst [deleted file]
typo3/sysext/dbal/Documentation/InstallingWithDbal/DoingTheActualSetup/Index.rst [deleted file]
typo3/sysext/dbal/Documentation/InstallingWithDbal/Index.rst [deleted file]
typo3/sysext/dbal/Documentation/InstallingWithDbal/Introduction/Index.rst [deleted file]
typo3/sysext/dbal/Documentation/InstallingWithDbal/PreparingSetup/Index.rst [deleted file]
typo3/sysext/dbal/Documentation/Introduction/Index.rst [deleted file]
typo3/sysext/dbal/Documentation/KnownProblems/ChangingOfTableOrFieldDefinitionsThroughDbal/Index.rst [deleted file]
typo3/sysext/dbal/Documentation/KnownProblems/CreatingADatabaseFromWithinTheInstallTool/Index.rst [deleted file]
typo3/sysext/dbal/Documentation/KnownProblems/DatabaseCheckInBackend/Index.rst [deleted file]
typo3/sysext/dbal/Documentation/KnownProblems/DatabaseSpecificIssues/Index.rst [deleted file]
typo3/sysext/dbal/Documentation/KnownProblems/Index.rst [deleted file]
typo3/sysext/dbal/Documentation/KnownProblems/ResultsOfDatabaseComparisonOperations/Index.rst [deleted file]
typo3/sysext/dbal/Documentation/KnownProblems/SequencesCollideWithImportedData/Index.rst [deleted file]
typo3/sysext/dbal/Documentation/KnownProblems/SomeFieldNamesAreTooLong/Index.rst [deleted file]
typo3/sysext/dbal/Documentation/Settings.cfg [deleted file]
typo3/sysext/dbal/Documentation/Settings.yml [deleted file]
typo3/sysext/dbal/Documentation/Targets.rst [deleted file]
typo3/sysext/dbal/Documentation/To-doList/GeneralTodo/Index.rst [deleted file]
typo3/sysext/dbal/Documentation/To-doList/Index.rst [deleted file]
typo3/sysext/dbal/Documentation/To-doList/NewFeatures/Index.rst [deleted file]
typo3/sysext/dbal/Documentation/To-doList/Oracle/Index.rst [deleted file]
typo3/sysext/dbal/Resources/Private/Language/locallang.xlf [deleted file]
typo3/sysext/dbal/Resources/Private/Language/locallang_em.xlf [deleted file]
typo3/sysext/dbal/Resources/Private/Language/locallang_mod.xlf [deleted file]
typo3/sysext/dbal/Resources/Public/Icons/module-dbal.svg [deleted file]
typo3/sysext/dbal/Tests/Unit/Database/AbstractTestCase.php [deleted file]
typo3/sysext/dbal/Tests/Unit/Database/DatabaseConnectionMssqlTest.php [deleted file]
typo3/sysext/dbal/Tests/Unit/Database/DatabaseConnectionOracleTest.php [deleted file]
typo3/sysext/dbal/Tests/Unit/Database/DatabaseConnectionPostgresqlTest.php [deleted file]
typo3/sysext/dbal/Tests/Unit/Database/DatabaseConnectionTest.php [deleted file]
typo3/sysext/dbal/Tests/Unit/Database/DatabaseSpecificsPostgresqlTest.php [deleted file]
typo3/sysext/dbal/Tests/Unit/Database/DatabaseSpecificsTest.php [deleted file]
typo3/sysext/dbal/Tests/Unit/Database/SqlParserTest.php [deleted file]
typo3/sysext/dbal/Tests/Unit/Service/SqlSchemaMigrationServiceTest.php [deleted file]
typo3/sysext/dbal/composer.json [deleted file]
typo3/sysext/dbal/ext_conf_template.txt [deleted file]
typo3/sysext/dbal/ext_emconf.php [deleted file]
typo3/sysext/dbal/ext_icon.png [deleted file]
typo3/sysext/dbal/ext_localconf.php [deleted file]
typo3/sysext/dbal/ext_tables.php [deleted file]
typo3/sysext/dbal/ext_tables.sql [deleted file]
typo3/sysext/dbal/res/README [deleted file]
typo3/sysext/dbal/res/oracle/indexed_search.diff [deleted file]
typo3/sysext/dbal/res/oracle/scheduler.diff [deleted file]
typo3/sysext/dbal/res/postgresql/postgresql-compatibility.sql [deleted file]
typo3/sysext/install/Classes/Controller/AbstractController.php
typo3/sysext/install/Classes/Updates/DbalAndAdodbExtractionUpdate.php [new file with mode: 0644]
typo3/sysext/install/ext_localconf.php

index b79982a..ffa58dc 100644 (file)
@@ -91,7 +91,6 @@
                "typo3/cms-compatibility7": "self.version",
                "typo3/cms-cshmanual": "self.version",
                "typo3/cms-css-styled-content": "self.version",
-               "typo3/cms-dbal": "self.version",
                "typo3/cms-documentation": "self.version",
                "typo3/cms-extbase": "self.version",
                "typo3/cms-extensionmanager": "self.version",
                        "TYPO3\\CMS\\Core\\": "typo3/sysext/core/Classes/",
                        "TYPO3\\CMS\\Cshmanual\\": "typo3/sysext/cshmanual/Classes/",
                        "TYPO3\\CMS\\CssStyledContent\\": "typo3/sysext/css_styled_content/Classes/",
-                       "TYPO3\\CMS\\Dbal\\": "typo3/sysext/dbal/Classes/",
                        "TYPO3\\CMS\\Documentation\\": "typo3/sysext/documentation/Classes/",
                        "TYPO3\\CMS\\Extbase\\": "typo3/sysext/extbase/Classes/",
                        "TYPO3\\CMS\\Extensionmanager\\": "typo3/sysext/extensionmanager/Classes/",
                        "TYPO3\\CMS\\Belog\\Tests\\": "typo3/sysext/belog/Tests/",
                        "TYPO3\\CMS\\Beuser\\Tests\\": "typo3/sysext/beuser/Tests/",
                        "TYPO3\\CMS\\Core\\Tests\\": "typo3/sysext/core/Tests/",
-                       "TYPO3\\CMS\\Dbal\\Tests\\": "typo3/sysext/dbal/Tests/",
                        "TYPO3\\CMS\\Documentation\\Tests\\": "typo3/sysext/documentation/Tests/",
                        "TYPO3\\CMS\\Extbase\\Tests\\": "typo3/sysext/extbase/Tests/",
                        "TYPO3\\CMS\\Extensionmanager\\Tests\\": "typo3/sysext/extensionmanager/Tests/",
index 031b27e..663ed72 100644 (file)
@@ -4,8 +4,8 @@
         "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
         "This file is @generated automatically"
     ],
-    "hash": "46a2263f63778c3f9e77f69e9fcccd66",
-    "content-hash": "ddec27f96ce9faecb83d4c9f8ae46d5b",
+    "hash": "eee83d589f64ac1a4a248ca86847381b",
+    "content-hash": "b8a638b8c136516c6ca50bf2636bd151",
     "packages": [
         {
             "name": "cogpowered/finediff",
             "version": "v1.1.6",
             "source": {
                 "type": "git",
-                "url": "https://github.com/site5/phantoman.git",
+                "url": "https://github.com/grantlucas/phantoman.git",
                 "reference": "6ac9bed985d023909966a5c5b82489ced62998d1"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/site5/phantoman/zipball/6ac9bed985d023909966a5c5b82489ced62998d1",
+                "url": "https://api.github.com/repos/grantlucas/phantoman/zipball/6ac9bed985d023909966a5c5b82489ced62998d1",
                 "reference": "6ac9bed985d023909966a5c5b82489ced62998d1",
                 "shasum": ""
             },
diff --git a/typo3/sysext/core/Documentation/Changelog/master/Breaking-77762-ExtensionsDbalAndAdodbMovedToTER.rst b/typo3/sysext/core/Documentation/Changelog/master/Breaking-77762-ExtensionsDbalAndAdodbMovedToTER.rst
new file mode 100644 (file)
index 0000000..9e136f9
--- /dev/null
@@ -0,0 +1,26 @@
+=========================================================
+Breaking: #77762 - Extensions dbal and adodb moved to TER
+=========================================================
+
+Description
+===========
+
+The legacy extensions ``dbal`` and ``adodb`` have been removed from the TYPO3 CMS core and are only available as TER extension.
+
+
+Impact
+======
+
+Tables located on non-MySQL databases stop working until ``adodb`` and ``dbal`` are installed from TER if a third party extensions uses the old ``TYPO3_DB`` API to query those tables.
+
+
+Affected Installations
+======================
+
+Most installations are not affected. Instances are only affected if a loaded extension uses the old ``TYPO3_DB`` database API, if ``dbal`` and ``adodb`` have been loaded and if an active table mapping to non-MySQL databases is configured.
+
+
+Migration
+=========
+
+Use the upgrade wizard provided by the install tool to fetch and load the extensions from TER.
\ No newline at end of file
diff --git a/typo3/sysext/dbal/Classes/Controller/ModuleController.php b/typo3/sysext/dbal/Classes/Controller/ModuleController.php
deleted file mode 100644 (file)
index e45a720..0000000
+++ /dev/null
@@ -1,648 +0,0 @@
-<?php
-namespace TYPO3\CMS\Dbal\Controller;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * 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.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-use Psr\Http\Message\ResponseInterface;
-use Psr\Http\Message\ServerRequestInterface;
-use TYPO3\CMS\Backend\Module\BaseScriptClass;
-use TYPO3\CMS\Backend\Template\ModuleTemplate;
-use TYPO3\CMS\Backend\Utility\BackendUtility;
-use TYPO3\CMS\Core\Database\DatabaseConnection;
-use TYPO3\CMS\Core\Utility\GeneralUtility;
-
-/**
- * Script class; Backend module for DBAL extension
- */
-class ModuleController extends BaseScriptClass
-{
-    /**
-     * @var string
-     */
-    protected $thisScript;
-
-    /**
-     * The name of the module
-     *
-     * @var string
-     */
-    protected $moduleName = 'tools_txdbalM1';
-
-    /**
-     * ModuleTemplateContainer
-     *
-     * @var ModuleTemplate
-     */
-    protected $moduleTemplate;
-
-    /**
-     * Initializes this module.
-     *
-     * @return void
-     */
-    public function init()
-    {
-        $this->MCONF = [
-            'name' => $this->moduleName,
-        ];
-        $this->getLanguageService()->includeLLFile('EXT:dbal/Resources/Private/Language/locallang.xlf');
-        parent::init();
-        $this->moduleTemplate = GeneralUtility::makeInstance(ModuleTemplate::class);
-    }
-
-    /**
-     * Adds items to the ->MOD_MENU array. Used for the function menu selector.
-     *
-     * @return void
-     */
-    public function menuConfig()
-    {
-        $languageService = $this->getLanguageService();
-        $this->MOD_MENU = [
-            'function' => [
-                0 => $languageService->getLL('Debug_log'),
-                'info' => $languageService->getLL('Cached_info'),
-                'sqlcheck' => $languageService->getLL('SQL_check')
-            ]
-        ];
-        parent::menuConfig();
-    }
-
-    /**
-     * Main function of the module. Write the content to $this->content
-     *
-     * @return void
-     */
-    public function main()
-    {
-        $languageService = $this->getLanguageService();
-        $this->thisScript = BackendUtility::getModuleUrl($this->MCONF['name']);
-        // Clean up settings:
-        $this->MOD_SETTINGS = BackendUtility::getModuleData(
-            $this->MOD_MENU,
-            GeneralUtility::_GP('SET'),
-            $this->MCONF['name']
-        );
-        // Draw the header
-        // DBAL page title:
-        $this->content .= '<h1>' . $languageService->getLL('title') . '</h1>';
-        $this->generateMenu();
-        $shortcutName = $languageService->getLL('Debug_log');
-        // Debug log:
-        switch ($this->MOD_SETTINGS['function']) {
-            case 'info':
-                $this->content .= '<h3>' . $languageService->getLL('Cached_info') . '</h3>';
-                $this->content .= '<div>' . $this->printCachedInfo() . '</div>';
-                $shortcutName = $languageService->getLL('Cached_info');
-                break;
-            case 'sqlcheck':
-                $this->content .= '<h3>' . $languageService->getLL('SQL_check') . '</h3>';
-                $this->content .= '<div>' . $this->printSqlCheck() . '</div>';
-                $shortcutName = $languageService->getLL('SQL_check');
-                break;
-            case 0:
-                $this->content .= '<h3>' . $languageService->getLL('Debug_log') . '</h3>';
-                $this->content .= '<div>' . $this->printLogMgm() . '</div>';
-                break;
-        }
-        // ShortCut
-        $shortcutButton = $this->moduleTemplate->getDocHeaderComponent()->getButtonBar()->makeShortcutButton()
-            ->setModuleName($this->MCONF['name'])
-            ->setDisplayName($shortcutName)
-            ->setSetVariables(['function']);
-        $this->moduleTemplate->getDocHeaderComponent()->getButtonBar()->addButton($shortcutButton);
-    }
-
-    /**
-     * Injects the request object for the current request or subrequest
-     * As this controller goes only through the main() method, it is rather simple for now
-     *
-     * @param ServerRequestInterface $request the current request
-     * @param ResponseInterface $response
-     * @return ResponseInterface the response with the content
-     */
-    public function mainAction(ServerRequestInterface $request, ResponseInterface $response)
-    {
-        $GLOBALS['SOBE'] = $this;
-        $this->init();
-        $this->main();
-        $this->moduleTemplate->setContent($this->content);
-        $response->getBody()->write($this->moduleTemplate->renderContent());
-        return $response;
-    }
-
-    /**
-     * Displays a form to check DBAL SQL methods and parse raw SQL.
-     *
-     * @return string HTML output
-     */
-    protected function printSqlCheck()
-    {
-        $input = GeneralUtility::_GP('tx_dbal');
-        $out = '
-                       <form name="sql_check" action="' . $this->thisScript . '" method="post" enctype="multipart/form-data">
-                       <script type="text/javascript">
-/*<![CDATA[*/
-function updateQryForm(s) {
-       document.getElementById(\'tx-dbal-result\').style.display = \'none\';
-       switch(s) {
-               case \'SELECT\':
-                       document.getElementById(\'tx-dbal-qryupdate\').style.display = \'none\';
-                       document.getElementById(\'tx-dbal-qryfields\').style.display = \'table-row\';
-                       document.getElementById(\'tx-dbal-qryinsertvalues\').style.display = \'none\';
-                       document.getElementById(\'tx-dbal-qryupdatevalues\').style.display = \'none\';
-                       document.getElementById(\'tx-dbal-qryfrom\').style.display = \'table-row\';
-                       document.getElementById(\'tx-dbal-qryinto\').style.display = \'none\';
-                       document.getElementById(\'tx-dbal-qrywhere\').style.display = \'table-row\';
-                       document.getElementById(\'tx-dbal-qrygroup\').style.display = \'table-row\';
-                       document.getElementById(\'tx-dbal-qryorder\').style.display = \'table-row\';
-                       document.getElementById(\'tx-dbal-qrylimit\').style.display = \'table-row\';
-               break;
-               case \'INSERT\':
-                       document.getElementById(\'tx-dbal-qryupdate\').style.display = \'none\';
-                       document.getElementById(\'tx-dbal-qryfields\').style.display = \'none\';
-                       document.getElementById(\'tx-dbal-qryinsertvalues\').style.display = \'table-row\';
-                       document.getElementById(\'tx-dbal-qryupdatevalues\').style.display = \'none\';
-                       document.getElementById(\'tx-dbal-qryfrom\').style.display = \'none\';
-                       document.getElementById(\'tx-dbal-qryinto\').style.display = \'table-row\';
-                       document.getElementById(\'tx-dbal-qrywhere\').style.display = \'table-row\';
-                       document.getElementById(\'tx-dbal-qrygroup\').style.display = \'table-row\';
-                       document.getElementById(\'tx-dbal-qryorder\').style.display = \'table-row\';
-                       document.getElementById(\'tx-dbal-qrylimit\').style.display = \'table-row\';
-               break;
-               case \'UPDATE\':
-                       document.getElementById(\'tx-dbal-qryupdate\').style.display = \'table-row\';
-                       document.getElementById(\'tx-dbal-qryfields\').style.display = \'none\';
-                       document.getElementById(\'tx-dbal-qryinsertvalues\').style.display = \'none\';
-                       document.getElementById(\'tx-dbal-qryupdatevalues\').style.display = \'table-row\';
-                       document.getElementById(\'tx-dbal-qryfrom\').style.display = \'none\';
-                       document.getElementById(\'tx-dbal-qryinto\').style.display = \'none\';
-                       document.getElementById(\'tx-dbal-qryupdate\').style.display = \'table-row\';
-                       document.getElementById(\'tx-dbal-qrywhere\').style.display = \'table-row\';
-                       document.getElementById(\'tx-dbal-qrygroup\').style.display = \'none\';
-                       document.getElementById(\'tx-dbal-qryorder\').style.display = \'none\';
-                       document.getElementById(\'tx-dbal-qrylimit\').style.display = \'none\';
-               break;
-               case \'DELETE\':
-                       document.getElementById(\'tx-dbal-qryupdate\').style.display = \'none\';
-                       document.getElementById(\'tx-dbal-qryfields\').style.display = \'none\';
-                       document.getElementById(\'tx-dbal-qryinsertvalues\').style.display = \'none\';
-                       document.getElementById(\'tx-dbal-qryupdatevalues\').style.display = \'none\';
-                       document.getElementById(\'tx-dbal-qryfrom\').style.display = \'table-row\';
-                       document.getElementById(\'tx-dbal-qryinto\').style.display = \'none\';
-                       document.getElementById(\'tx-dbal-qrywhere\').style.display = \'table-row\';
-                       document.getElementById(\'tx-dbal-qrygroup\').style.display = \'none\';
-                       document.getElementById(\'tx-dbal-qryorder\').style.display = \'none\';
-                       document.getElementById(\'tx-dbal-qrylimit\').style.display = \'none\';
-               break;
-       }
-}
-/*]]>*/
-                               </script>
-           <table>
-           <tr class="tableheader"><th colspan="2">Easy SQL check</th></tr>
-           <tr><td colspan="2">
-           <select name="tx_dbal[QUERY]"size="1" onchange="updateQryForm(this.options[this.selectedIndex].value)">
-            <option value="SELECT" ' . ($input['QUERY'] === 'SELECT' ? 'selected="selected"' : '') . '>SELECT</option>
-            <option value="INSERT" ' . ($input['QUERY'] === 'INSERT' ? 'selected="selected"' : '') . '>INSERT</option>
-            <option value="UPDATE" ' . ($input['QUERY'] === 'UPDATE' ? 'selected="selected"' : '') . '>UPDATE</option>
-            <option value="DELETE" ' . ($input['QUERY'] === 'DELETE' ? 'selected="selected"' : '') . '>DELETE</option>
-           </select>
-           </td></tr>
-           <tr id="tx-dbal-qryupdate" style="display:none;"><td></td><td><input name="tx_dbal[UPDATE]" value="' . $input['UPDATE'] . '" type="text" size="30" maxsize="100" /></td></tr>
-           <tr id="tx-dbal-qryfields"><td></td><td><input name="tx_dbal[FIELDS]" value="' . $input['FIELDS'] . '" type="text" size="30" maxsize="100" /></td></tr>
-           <tr id="tx-dbal-qryinsertvalues" style="display:none;"><td></td><td><textarea name="tx_dbal[INSERTVALUES]" cols="30" rows="4">' . $input['INSERTVALUES'] . '</textarea></td></tr>
-           <tr id="tx-dbal-qryupdatevalues" style="display:none;"><th>SET</th><td><textarea name="tx_dbal[UPDATEVALUES]" cols="30" rows="4">' . $input['UPDATEVALUES'] . '</textarea></td></tr>
-           <tr id="tx-dbal-qryfrom"><th>FROM</th><td><input name="tx_dbal[FROM]" value="' . $input['FROM'] . '" type="text" size="30" maxsize="100" /></td></tr>
-           <tr id="tx-dbal-qryinto" style="display:none;"><th>INTO</th><td><input name="tx_dbal[INTO]" value="' . $input['INTO'] . '" type="text" size="30" maxsize="100" /></td></tr>
-           <tr id="tx-dbal-qrywhere"><th>WHERE</th><td><input name="tx_dbal[WHERE]" value="' . $input['WHERE'] . '" type="text" size="30" maxsize="100" /></td></tr>
-           <tr id="tx-dbal-qrygroup"><th>GROUP BY</th><td><input name="tx_dbal[GROUP]" value="' . $input['GROUP'] . '" type="text" size="30" maxsize="100" /></td></tr>
-           <tr id="tx-dbal-qryorder"><th>ORDER BY</th><td><input name="tx_dbal[ORDER]" value="' . $input['ORDER'] . '" type="text" size="30" maxsize="100" /></td></tr>
-           <tr id="tx-dbal-qrylimit"><th>LIMIT</th><td><input name="tx_dbal[LIMIT]" value="' . $input['LIMIT'] . '" type="text" size="30" maxsize="100" /></td></tr>
-               <tr>
-                       <td></td>
-                       <td style="text-align:right;">
-                               <input class="btn btn-default" type="submit" value="CHECK" />
-                       </td>
-               </tr>
-                       <script type="text/javascript">
-/*<![CDATA[*/
-updateQryForm(\'' . $input['QUERY'] . '\');
-/*]]>*/
-                               </script>
-                       ';
-        $out .= '<tr id="tx-dbal-result"><th>Result:</th><td>';
-        switch ($input['QUERY']) {
-            case 'SELECT':
-                $qry = $this->getDatabaseConnection()->SELECTquery($input['FIELDS'], $input['FROM'], $input['WHERE'], $input['GROUP'], $input['ORDER'], $input['LIMIT']);
-                break;
-            case 'INSERT':
-                $qry = $this->getDatabaseConnection()->INSERTquery($input['INTO'], $this->createFieldsValuesArray($input['INSERTVALUES']));
-                break;
-            case 'UPDATE':
-                $qry = $GLOBALS['TYPO3_DB']->UPDATEquery($input['UPDATE'], $input['WHERE'], $this->createFieldsValuesArray($input['UPDATEVALUES']));
-                break;
-            case 'DELETE':
-                $qry = $GLOBALS['TYPO3_DB']->DELETEquery($input['FROM'], $input['WHERE']);
-                break;
-        }
-        $out .= '<pre>' . htmlspecialchars($qry) . '</pre></td></tr>';
-        $out .= '
-                       <tr class="tableheader">
-                               <th colspan="2">RAW SQL check</th>
-                       </tr>
-                       <tr>
-                               <td colspan="2" style="text-align:right;">
-                                       <textarea name="tx_dbal[RAWSQL]" cols="60" rows="5">' . $input['RAWSQL'] . '</textarea>
-                                       <br />
-                                       <input class="btn btn-default" type="submit" value="CHECK" />
-                               </td>
-                       </tr>';
-        if (!empty($input['RAWSQL'])) {
-            $out .= '<tr>';
-            $parseResult = $GLOBALS['TYPO3_DB']->SQLparser->parseSQL($input['RAWSQL']);
-            if (is_array($parseResult)) {
-                $newQuery = $GLOBALS['TYPO3_DB']->SQLparser->compileSQL($parseResult);
-                $testResult = $GLOBALS['TYPO3_DB']->SQLparser->debug_parseSQLpartCompare($input['RAWSQL'], $newQuery);
-                if (!is_array($testResult)) {
-                    $out .= '<td colspan="2">' . $newQuery;
-                } else {
-                    $out .= '<td colspan="2">' . htmlspecialchars($testResult[0]) . '</td></tr>
-                                       <tr><th>Error:</th><td style="border:2px solid #f00;">Input query did not match the parsed and recompiled query exactly (not observing whitespace):<br />' . htmlspecialchars($testResult[1]);
-                }
-            } else {
-                $out .= '<th>Result:</th><td style="border:2px solid #f00;">' . $parseResult;
-            }
-            $out .= '</td></tr>';
-        }
-        $out .= '</table></form>';
-        return $out;
-    }
-
-    /**
-     * Parses a very simple text format into an array.
-     *
-     * Each line is seen as a key/value pair that is exploded at =. This is used
-     * in the simple SQL check to input values for INSERT and UPDATE statements.
-     *
-     * @param string $in String to parse into key/value array.
-     * @return array Array created from the input string.
-     */
-    protected function createFieldsValuesArray($in)
-    {
-        $ret = [];
-        $in = explode(LF, $in);
-        foreach ($in as $v) {
-            $fv = explode('=', $v);
-            $ret[$fv[0]] = $fv[1];
-        }
-        return $ret;
-    }
-
-    /**
-     * Prints out the cached information about the database.
-     *
-     * The DBAL caches a lot of information, e.g. about auto increment fields,
-     * field types and primary keys. This method formats all this into a HTML
-     * table to display in the BE.
-     *
-     * @return string
-     */
-    protected function printCachedInfo()
-    {
-        // Get cmd:
-        if ((string)GeneralUtility::_GP('cmd') === 'clear') {
-            $this->getDatabaseConnection()->clearCachedFieldInfo();
-            $GLOBALS['TYPO3_DB']->cacheFieldInfo();
-        }
-        $out = '<a name="autoincrement"></a><h2>auto_increment</h2>';
-        $out .= '<table border="1" cellspacing="0"><tbody><tr><th>Table</th><th>Field</th></tr>';
-        ksort($GLOBALS['TYPO3_DB']->cache_autoIncFields);
-        foreach ($GLOBALS['TYPO3_DB']->cache_autoIncFields as $table => $field) {
-            $out .= '<tr>';
-            $out .= '<td>' . $table . '</td>';
-            $out .= '<td>' . $field . '</td>';
-            $out .= '</tr>';
-        }
-        $out .= '</tbody></table>';
-        $out .= '<a name="primarykeys"></a><h2>Primary keys</h2>';
-        $out .= '<table border="1" cellspacing="0"><tbody><tr><th>Table</th><th>Field(s)</th></tr>';
-        ksort($GLOBALS['TYPO3_DB']->cache_primaryKeys);
-        foreach ($GLOBALS['TYPO3_DB']->cache_primaryKeys as $table => $field) {
-            $out .= '<tr>';
-            $out .= '<td>' . $table . '</td>';
-            $out .= '<td>' . $field . '</td>';
-            $out .= '</tr>';
-        }
-        $out .= '</tbody></table>';
-        $out .= '<a name="fieldtypes"></a><h2>Field types</h2>';
-        $out .= '
-            <table border="1" cellspacing="0">
-                <tbody>
-                    <tr>
-                        <th colspan="5">Table</th>
-                    </tr>
-                    <tr>
-                        <th>Field</th>
-                        <th>Type</th><th>
-                        <a href="#metatypes">Metatype</a></th>
-                        <th>NOT NULL</th>
-                        <th>Default</th></th>
-                    </tr>';
-        ksort($GLOBALS['TYPO3_DB']->cache_fieldType);
-        foreach ($GLOBALS['TYPO3_DB']->cache_fieldType as $table => $fields) {
-            $out .= '<th colspan="5">' . $table . '</th>';
-            foreach ($fields as $field => $data) {
-                $out .= '<tr>';
-                $out .= '<td>' . $field . '</td>';
-                $out .= '<td>' . $data['type'] . '</td>';
-                $out .= '<td>' . $data['metaType'] . '</td>';
-                $out .= '<td>' . ($data['notnull'] ? 'NOT NULL' : '') . '</td>';
-                $out .= '<td>' . $data['default'] . '</td>';
-                $out .= '</tr>';
-            }
-        }
-        $out .= '</tbody></table>';
-        $out .= '<a name="metatypes"></a><h2>Metatype explanation</h2>';
-        $out .= '<pre>
-  C:  Varchar, capped to 255 characters.
-  X:  Larger varchar, capped to 4000 characters (to be compatible with Oracle).
-  XL: For Oracle, returns CLOB, otherwise the largest varchar size.
-
-  C2: Multibyte varchar
-  X2: Multibyte varchar (largest size)
-
-  B:  BLOB (binary large object)
-
-  D:  Date (some databases do not support this, and we return a datetime type)
-  T:  Datetime or Timestamp
-  L:  Integer field suitable for storing booleans (0 or 1)
-  I:  Integer (mapped to I4)
-  I1: 1-byte integer
-  I2: 2-byte integer
-  I4: 4-byte integer
-  I8: 8-byte integer
-  F:  Floating point number
-  N:  Numeric or decimal number</pre>';
-        $menu = '<a href="' . $this->thisScript . '&amp;cmd=clear">CLEAR DATA</a><hr />';
-        $menu .= '<a href="#autoincrement">auto_increment</a> | <a href="#primarykeys">Primary keys</a> | <a href="#fieldtypes">Field types</a> | <a href="#metatypes">Metatype explanation</a><hr />';
-        return $menu . $out;
-    }
-
-    /**
-     * Printing the debug-log from the DBAL extension
-     *
-     * To enabled debugging, you will have to enabled it in the configuration!
-     *
-     * @return         string HTML content
-     */
-    protected function printLogMgm()
-    {
-        // Disable debugging in any case...
-        $GLOBALS['TYPO3_DB']->debug = false;
-        // Get cmd:
-        $cmd = (string)GeneralUtility::_GP('cmd');
-        switch ($cmd) {
-            case 'flush':
-                $res = $GLOBALS['TYPO3_DB']->exec_TRUNCATEquery('tx_dbal_debuglog');
-                $res = $GLOBALS['TYPO3_DB']->exec_TRUNCATEquery('tx_dbal_debuglog_where');
-                $outStr = 'Log FLUSHED!';
-                break;
-            case 'joins':
-                $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('table_join,exec_time,query,script', 'tx_dbal_debuglog', 'table_join!=\'\'', 'table_join,script,exec_time,query');
-                // Init vars in which to pick up the query result:
-                $tableIndex = [];
-                $tRows = [];
-                $tRows[] = '
-                                               <tr>
-                                                       <td>Execution time</td>
-                                                       <td>Table joins</td>
-                                                       <td>Script</td>
-                                                       <td>Query</td>
-                                               </tr>';
-                while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
-                    $tableArray = $GLOBALS['TYPO3_DB']->SQLparser->parseFromTables($row['table_join']);
-                    // Create table name index:
-                    foreach ($tableArray as $a) {
-                        foreach ($tableArray as $b) {
-                            if ($b['table'] != $a['table']) {
-                                $tableIndex[$a['table']][$b['table']] = 1;
-                            }
-                        }
-                    }
-                    // Create output row
-                    $tRows[] = '
-                                                       <tr>
-                                                               <td>' . htmlspecialchars($row['exec_time']) . '</td>
-                                                               <td>' . htmlspecialchars($row['table_join']) . '</td>
-                                                               <td>' . htmlspecialchars($row['script']) . '</td>
-                                                               <td>' . htmlspecialchars($row['query']) . '</td>
-                                                       </tr>';
-                }
-                // Printing direct joins:
-                $outStr .= '<h4>Direct joins:</h4>' . \TYPO3\CMS\Core\Utility\DebugUtility::viewArray($tableIndex);
-                // Printing total dependencies:
-                foreach ($tableIndex as $priTable => $a) {
-                    foreach ($tableIndex as $tableN => $v) {
-                        foreach ($v as $tableP => $vv) {
-                            if ($tableP == $priTable) {
-                                $tableIndex[$priTable] = array_merge($v, $a);
-                            }
-                        }
-                    }
-                }
-                $outStr .= '<h4>Total dependencies:</h4>' . \TYPO3\CMS\Core\Utility\DebugUtility::viewArray($tableIndex);
-                // Printing data rows:
-                $outStr .= '
-                                               <table border="1" cellspacing="0">' . implode('', $tRows) . '
-                                               </table>';
-                break;
-            case 'errors':
-                $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('serdata,exec_time,query,script', 'tx_dbal_debuglog', 'errorFlag>0', '', 'tstamp DESC');
-                // Init vars in which to pick up the query result:
-                $tRows = [];
-                $tRows[] = '
-                                               <tr>
-                                                       <td>Execution time</td>
-                                                       <td>Error data</td>
-                                                       <td>Script</td>
-                                                       <td>Query</td>
-                                               </tr>';
-                while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
-                    // Create output row
-                    $tRows[] = '
-                                                       <tr>
-                                                               <td>' . htmlspecialchars($row['exec_time']) . '</td>
-                                                               <td>' . \TYPO3\CMS\Core\Utility\DebugUtility::viewArray(unserialize($row['serdata'])) . '</td>
-                                                               <td>' . htmlspecialchars($row['script']) . '</td>
-                                                               <td>' . htmlspecialchars($row['query']) . '</td>
-                                                       </tr>';
-                }
-                // Printing data rows:
-                $outStr .= '
-                                               <table border="1" cellspacing="0">' . implode('', $tRows) . '
-                                               </table>';
-                break;
-            case 'parsing':
-                $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('query,serdata', 'tx_dbal_debuglog', 'errorFlag&2=2');
-                $tRows = [];
-                while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
-                    // Create output row
-                    $tRows[] = '
-                                                       <tr>
-                                                               <td>' . htmlspecialchars($row['query']) . '</td>
-                                                       </tr>';
-                }
-                // Printing data rows:
-                $outStr .= '
-                                               <table border="1" cellspacing="0">' . implode('', $tRows) . '
-                                               </table>';
-                break;
-            case 'where':
-                $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('tstamp,script,tablename,whereclause', 'tx_dbal_debuglog_where', '', '', 'tstamp DESC');
-                $tRows = [];
-                $tRows[] = '
-                                               <tr>
-                                                       <td>Time</td>
-                                                       <td>Script</td>
-                                                       <td>Table</td>
-                                                       <td>WHERE clause</td>
-                                               </tr>';
-                while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
-                    $tRows[] = '
-                                                       <tr>
-                                                               <td>' . BackendUtility::datetime($row['tstamp']) . '</td>
-                                                               <td>' . htmlspecialchars($row['script']) . '</td>
-                                                               <td>' . htmlspecialchars($row['tablename']) . '</td>
-                                                                       <td>' . str_replace(['\'\'', '""', 'IS NULL', 'IS NOT NULL'], ['<span style="background-color:#ff0000;color:#ffffff;padding:2px;font-weight:bold;">\'\'</span>', '<span style="background-color:#ff0000;color:#ffffff;padding:2px;font-weight:bold;">""</span>', '<span style="background-color:#00ff00;color:#ffffff;padding:2px;font-weight:bold;">IS NULL</span>', '<span style="background-color:#00ff00;color:#ffffff;padding:2px;font-weight:bold;">IS NOT NULL</span>'], htmlspecialchars($row['whereclause'])) . '</td>
-                                                       </tr>';
-                }
-                $outStr = '
-                                               <table border="1" cellspacing="0">' . implode('', $tRows) . '
-                                               </table>';
-                break;
-            default:
-                // Look for request to view specific script exec:
-                $specTime = GeneralUtility::_GP('specTime');
-                if ($specTime) {
-                    $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('exec_time,errorFlag,table_join,serdata,query', 'tx_dbal_debuglog', 'tstamp=' . (int)$specTime);
-                    $tRows = [];
-                    $tRows[] = '
-                                                       <tr>
-                                                               <td>Execution time</td>
-                                                               <td>Error</td>
-                                                               <td>Table joins</td>
-                                                               <td>Data</td>
-                                                               <td>Query</td>
-                                                       </tr>';
-                    while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
-                        $tRows[] = '
-                                                               <tr>
-                                                                       <td>' . htmlspecialchars($row['exec_time']) . '</td>
-                                                                       <td>' . ($row['errorFlag'] ? 1 : 0) . '</td>
-                                                                       <td>' . htmlspecialchars($row['table_join']) . '</td>
-                                                                       <td>' . \TYPO3\CMS\Core\Utility\DebugUtility::viewArray(unserialize($row['serdata'])) . '</td>
-                                                                       <td>' . str_replace(['\'\'', '""', 'IS NULL', 'IS NOT NULL'], ['<span style="background-color:#ff0000;color:#ffffff;padding:2px;font-weight:bold;">\'\'</span>', '<span style="background-color:#ff0000;color:#ffffff;padding:2px;font-weight:bold;">""</span>', '<span style="background-color:#00ff00;color:#ffffff;padding:2px;font-weight:bold;">IS NULL</span>', '<span style="background-color:#00ff00;color:#ffffff;padding:2px;font-weight:bold;">IS NOT NULL</span>'], htmlspecialchars($row['query'])) . '</td>
-                                                               </tr>';
-                    }
-                } else {
-                    $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('tstamp,script, SUM(exec_time) as calc_sum, count(*) AS qrycount, MAX(errorFlag) as error', 'tx_dbal_debuglog', '', 'tstamp,script', 'tstamp DESC');
-                    $tRows = [];
-                    $tRows[] = '
-                                                       <tr>
-                                                               <td>Time</td>
-                                                               <td># of queries</td>
-                                                               <td>Error</td>
-                                                               <td>Time (ms)</td>
-                                                               <td>Script</td>
-                                                       </tr>';
-                    while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
-                        $tRows[] = '
-                                                               <tr>
-                                                                       <td>' . BackendUtility::datetime($row['tstamp']) . '</td>
-                                                                       <td>' . htmlspecialchars($row['qrycount']) . '</td>
-                                                                       <td>' . ($row['error'] ? '<strong style="color:#f00">ERR</strong>' : '') . '</td>
-                                                                       <td>' . htmlspecialchars($row['calc_sum']) . '</td>
-                                                                       <td><a href="' . $this->thisScript . '&amp;specTime=' . (int)$row['tstamp'] . '">' . htmlspecialchars($row['script']) . '</a></td>
-                                                               </tr>';
-                    }
-                }
-                $outStr = '
-                                               <table border="1" cellspacing="0">' . implode('', $tRows) . '
-                                               </table>';
-        }
-        $menu = '
-                                       <a href="' . $this->thisScript . '&amp;cmd=flush">FLUSH LOG</a> -
-                                       <a href="' . $this->thisScript . '&amp;cmd=joins">JOINS</a> -
-                                       <a href="' . $this->thisScript . '&amp;cmd=errors">ERRORS</a> -
-                                       <a href="' . $this->thisScript . '&amp;cmd=parsing">PARSING</a> -
-                                       <a href="' . $this->thisScript . '">LOG</a> -
-                                       <a href="' . $this->thisScript . '&amp;cmd=where">WHERE</a> -
-
-                                       <a href="' . htmlspecialchars(GeneralUtility::linkThisScript()) . '" target="tx_debuglog">[New window]</a>
-                                       <hr />
-               ';
-        return $menu . $outStr;
-    }
-
-    /**
-     * Generate the ModuleMenu
-     */
-    protected function generateMenu()
-    {
-        $menu = $this->moduleTemplate->getDocHeaderComponent()->getMenuRegistry()->makeMenu();
-        $menu->setIdentifier('DBALJumpMenu');
-        foreach ($this->MOD_MENU['function'] as $controller => $title) {
-            $item = $menu
-                ->makeMenuItem()
-                ->setHref(
-                    BackendUtility::getModuleUrl(
-                        $this->moduleName,
-                        [
-                            'id' => $this->id,
-                            'SET' => [
-                                'function' => $controller
-                            ]
-                        ]
-                    )
-                )
-                ->setTitle($title);
-            if ($controller === $this->MOD_SETTINGS['function']) {
-                $item->setActive(true);
-            }
-            $menu->addMenuItem($item);
-        }
-        $this->moduleTemplate->getDocHeaderComponent()->getMenuRegistry()->addMenu($menu);
-    }
-
-    /**
-     * Returns the language service.
-     *
-     * @return \TYPO3\CMS\Lang\LanguageService
-     */
-    protected function getLanguageService()
-    {
-        return $GLOBALS['LANG'];
-    }
-
-    /**
-     * Returns the DatabaseConnection
-     *
-     * @return DatabaseConnection
-     */
-    protected function getDatabaseConnection()
-    {
-        return $GLOBALS['TYPO3_DB'];
-    }
-}
diff --git a/typo3/sysext/dbal/Classes/Database/AdodbPreparedStatement.php b/typo3/sysext/dbal/Classes/Database/AdodbPreparedStatement.php
deleted file mode 100644 (file)
index 6ad0c7d..0000000
+++ /dev/null
@@ -1,270 +0,0 @@
-<?php
-namespace TYPO3\CMS\Dbal\Database;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * 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.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-use TYPO3\CMS\Core\Utility\GeneralUtility;
-
-/**
- * MySQLi Prepared Statement-compatible implementation for ADOdb.
- *
- * Notice: Extends \TYPO3\CMS\Dbal\Database\DatabaseConnection to be able to access
- * protected properties solely (thus would be a "friend" class in C++).
- */
-class AdodbPreparedStatement extends \TYPO3\CMS\Dbal\Database\DatabaseConnection
-{
-    /**
-     * @var \TYPO3\CMS\Dbal\Database\DatabaseConnection
-     */
-    protected $databaseConnection;
-
-    /**
-     * @var string
-     */
-    protected $query;
-
-    /**
-     * @var array
-     */
-    protected $queryComponents;
-
-    /**
-     * @var array
-     */
-    protected $parameters;
-
-    /**
-     * @var \ADORecordSet_array
-     */
-    protected $recordSet;
-
-    /**
-     * Default constructor.
-     *
-     * @param string $query
-     * @param array $queryComponents
-     * @param \TYPO3\CMS\Dbal\Database\DatabaseConnection $databaseConnection
-     */
-    public function __construct($query, array $queryComponents, \TYPO3\CMS\Dbal\Database\DatabaseConnection $databaseConnection)
-    {
-        $this->databaseConnection = $databaseConnection;
-        $this->query = $query;
-        $this->queryComponents = $queryComponents;
-        $this->parameters = [];
-    }
-
-    /**
-     * Prepares an SQL statement for execution.
-     *
-     * @return bool TRUE on success or FALSE on failure
-     */
-    public function prepare()
-    {
-        // @todo actually prepare the query with ADOdb, if supported by the underlying DBMS
-        // see: http://phplens.com/lens/adodb/docs-adodb.htm#prepare
-        return true;
-    }
-
-    /**
-     * Transfers a result set from a prepared statement.
-     *
-     * @return TRUE on success or FALSE on failure
-     */
-    public function store_result()
-    {
-        return true;
-    }
-
-    /**
-     * Binds variables to a prepared statement as parameters.
-     *
-     * @param string $types
-     * @param mixed $var1 The number of variables and length of string types must match the parameters in the statement.
-     * @param mixed $_ [optional]
-     * @return bool TRUE on success or FALSE on failure
-     * @see \mysqli_stmt::bind_param()
-     */
-    public function bind_param($types, $var1, $_ = null)
-    {
-        $numberOfVariables = strlen($types);
-        if (func_num_args() !== $numberOfVariables + 1) {
-            return false;
-        }
-
-        $this->parameters = [
-            [
-                'type' => $types{0},
-                'value' => $var1
-            ],
-        ];
-        for ($i = 1; $i < $numberOfVariables; $i++) {
-            $this->parameters[] = [
-                'type' => $types{$i},
-                'value' => func_get_arg($i + 1),
-            ];
-        }
-
-        return true;
-    }
-
-    /**
-     * Resets a prepared statement.
-     *
-     * @return bool TRUE on success or FALSE on failure
-     */
-    public function reset()
-    {
-        return true;
-    }
-
-    /**
-     * Executes a prepared query.
-     *
-     * @return bool TRUE on success or FALSE on failure
-     */
-    public function execute()
-    {
-        $queryParts = $this->queryComponents['queryParts'];
-        $numberOfParameters = count($this->parameters);
-        for ($i = 0; $i < $numberOfParameters; $i++) {
-            $value = $this->parameters[$i]['value'];
-            switch ($this->parameters[$i]['type']) {
-                case 's':
-                    if ($value !== null) {
-                        $value = $this->databaseConnection->fullQuoteStr($value, $this->queryComponents['ORIG_tableName']);
-                    }
-                    break;
-                case 'i':
-                    $value = (int)$value;
-                    break;
-                default:
-                    // Same error as in \TYPO3\CMS\Core\Database\PreparedStatement::execute()
-                    throw new \InvalidArgumentException(sprintf('Unknown type %s used for parameter %s.', $this->parameters[$i]['type'], $i + 1), 1460975728);
-            }
-
-            $queryParts[$i * 2 + 1] = $value;
-        }
-
-        // Standard query from now on
-        $query = implode('', $queryParts);
-
-        $limit = $this->queryComponents['LIMIT'];
-        if ($this->databaseConnection->runningADOdbDriver('postgres')) {
-            // Possibly rewrite the LIMIT to be PostgreSQL-compatible
-            $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];
-                $limit = $numRows . ' OFFSET ' . $offset;
-            }
-        }
-        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;
-            }
-            $this->recordSet = $this->databaseConnection->handlerInstance[$this->databaseConnection->lastHandlerKey]->SelectLimit($query, $numRows, $offset);
-            $this->databaseConnection->lastQuery = $this->recordSet->sql;
-        } else {
-            $this->databaseConnection->lastQuery = $query;
-            $this->recordSet = $this->databaseConnection->handlerInstance[$this->databaseConnection->lastHandlerKey]->_Execute($this->databaseConnection->lastQuery);
-        }
-
-        if ($this->recordSet !== false) {
-            $success = true;
-            $this->recordSet->TYPO3_DBAL_handlerType = 'adodb';
-            // Setting handler type in result object (for later recognition!)
-            //$this->recordSet->TYPO3_DBAL_tableList = $queryComponents['ORIG_tableName'];
-        } else {
-            $success = false;
-        }
-
-        return $success;
-    }
-
-    /**
-     * Returns an array of objects representing the fields in a result set.
-     *
-     * @return array
-     */
-    public function fetch_fields()
-    {
-        return $this->recordSet !== false ? $this->recordSet->_fieldobjects : [];
-    }
-
-    /**
-     * Fetches a row from the underlying result set.
-     *
-     * @return array Array of rows or FALSE if there are no more rows.
-     */
-    public function fetch()
-    {
-        $row = $this->databaseConnection->sql_fetch_assoc($this->recordSet);
-        return $row;
-    }
-
-    /**
-     * Seeks to an arbitrary row in statement result set.
-     *
-     * @param int $offset Must be between zero and the total number of rows minus one
-     * @return bool TRUE on success or FALSE on failure
-     */
-    public function data_seek($offset)
-    {
-        return $this->databaseConnection->sql_data_seek($this->recordSet, $offset);
-    }
-
-    /**
-     * Closes a prepared statement.
-     *
-     * @return bool TRUE on success or FALSE on failure
-     */
-    public function close()
-    {
-        return $this->databaseConnection->sql_free_result($this->recordSet);
-    }
-
-    /**
-     * Magic getter for public properties of \mysqli_stmt access
-     * by \TYPO3\CMS\Core\Database\PreparedStatement.
-     *
-     * @param string $name
-     * @return mixed
-     */
-    public function __get($name)
-    {
-        switch ($name) {
-            case 'errno':
-                $output = $this->databaseConnection->sql_errno();
-                break;
-            case 'error':
-                $output = $this->databaseConnection->sql_error();
-                break;
-            case 'num_rows':
-                $output = $this->databaseConnection->sql_num_rows($this->recordSet);
-                break;
-            default:
-                throw new \RuntimeException('Cannot access property ' . $name, 1394631927);
-        }
-        return $output;
-    }
-}
diff --git a/typo3/sysext/dbal/Classes/Database/DatabaseConnection.php b/typo3/sysext/dbal/Classes/Database/DatabaseConnection.php
deleted file mode 100644 (file)
index 2b15311..0000000
+++ /dev/null
@@ -1,3990 +0,0 @@
-<?php
-namespace TYPO3\CMS\Dbal\Database;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * 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.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-use TYPO3\CMS\Core\Utility\GeneralUtility;
-
-/**
- * TYPO3 database abstraction layer
- */
-class DatabaseConnection extends \TYPO3\CMS\Core\Database\DatabaseConnection
-{
-    /**
-     * @var bool
-     */
-    protected $printErrors = false;
-
-    /**
-     * Enable output of SQL errors after query executions.
-     * @var bool
-     */
-    public $debug = false;
-
-    /**
-     * Enable debug mode
-     * @var bool
-     */
-    public $conf = [];
-
-    /**
-     * Configuration array, copied from TYPO3_CONF_VARS in constructor.
-     * @var array
-     */
-    public $mapping = [];
-
-    /**
-     * See manual
-     * @var array
-     */
-    protected $table2handlerKeys = [];
-
-    /**
-     * See manual
-     * @var array
-     */
-    public $handlerCfg = [
-        '_DEFAULT' => [
-            'type' => 'native',
-            'config' => [
-                'username' => '',
-                // Set by default (overridden)
-                'password' => '',
-                // Set by default (overridden)
-                'host' => '',
-                // Set by default (overridden)
-                'database' => '',
-                // Set by default (overridden)
-                'driver' => '',
-                // ONLY "adodb" type; eg. "mysql"
-                'sequenceStart' => 1,
-                // ONLY "adodb", first number in sequences/serials/...
-                'useNameQuote' => 0,
-                // ONLY "adodb", whether to use NameQuote() method from ADOdb to quote names
-                'quoteClob' => false
-            ]
-        ]
-    ];
-
-    /**
-     * 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 = [];
-
-    /**
-     * Storage of the handler key of last ( SELECT) query - used for subsequent fetch-row calls etc.
-     * @var string
-     */
-    public $lastHandlerKey = '';
-
-    /**
-     * Storage of last SELECT query
-     * @var string
-     */
-    protected $lastQuery = '';
-
-    /**
-     * The last parsed query array
-     * @var array
-     */
-    protected $lastParsedAndMappedQueryArray = [];
-
-    /**
-     * @var array
-     */
-    protected $resourceIdToTableNameMap = [];
-
-    /**
-     * @var array
-     */
-    protected $cache_handlerKeyFromTableList = [];
-
-    /**
-     * @var array
-     */
-    protected $cache_mappingFromTableList = [];
-
-    /**
-     * parsed SQL from standard DB dump file
-     * @var array
-     */
-    public $cache_autoIncFields = [];
-
-    /**
-     * @var array
-     */
-    public $cache_fieldType = [];
-
-    /**
-     * @var array
-     */
-    public $cache_primaryKeys = [];
-
-    /**
-     * @var string
-     */
-    protected $cacheIdentifier = 'DatabaseConnection_fieldInfo';
-
-    /**
-     * SQL parser
-     *
-     * @var \TYPO3\CMS\Dbal\Database\SqlParser
-     */
-    public $SQLparser;
-
-    /**
-     * @var \TYPO3\CMS\Install\Service\SqlSchemaMigrationService
-     */
-    protected $installerSql = null;
-
-    /**
-     * Cache for queries
-     *
-     * @var \TYPO3\CMS\Core\Cache\Frontend\VariableFrontend
-     */
-    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 = [
-        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 = 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'];
-    }
-
-    /**
-     * Initialize the database connection
-     *
-     * @return void
-     */
-    public function initialize()
-    {
-        // Set outside configuration:
-        if (isset($this->conf['mapping'])) {
-            $this->mapping = $this->conf['mapping'];
-        }
-        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 = !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('dbal_phpcode');
-    }
-
-    /**
-     * Clears the cached field information file.
-     *
-     * @return void
-     */
-    public function clearCachedFieldInfo()
-    {
-        $this->getFieldInfoCache()->flushByTag('DatabaseConnection');
-    }
-
-    /**
-     * Caches the field information.
-     *
-     * @return void
-     */
-    public function cacheFieldInfo()
-    {
-        $phpCodeCache = $this->getFieldInfoCache();
-        // try to fetch cache
-        // cache is flushed when admin_query() is called
-        if ($phpCodeCache->has($this->cacheIdentifier)) {
-            $fieldInformation = $phpCodeCache->requireOnce($this->cacheIdentifier);
-            $this->cache_autoIncFields = $fieldInformation['incFields'];
-            $this->cache_fieldType = $fieldInformation['fieldTypes'];
-            $this->cache_primaryKeys = $fieldInformation['primaryKeys'];
-        } else {
-            $this->analyzeCachingTables();
-            $this->analyzeExtensionTables();
-            $completeFieldInformation = $this->getCompleteFieldInformation();
-            $phpCodeCache->set($this->cacheIdentifier, $this->getCacheableString($completeFieldInformation), ['DatabaseConnection']);
-        }
-    }
-
-    /**
-     * Loop through caching configurations
-     * to find the usage of database backends and
-     * parse and analyze table definitions
-     *
-     * @return void
-     */
-    protected function analyzeCachingTables()
-    {
-        $schemaService = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Cache\DatabaseSchemaService::class);
-        $this->parseAndAnalyzeSql($schemaService->getCachingFrameworkRequiredDatabaseSchema());
-    }
-
-    /**
-     * Loop over all installed extensions
-     * parse and analyze table definitions (if any)
-     *
-     * @return void
-     */
-    protected function analyzeExtensionTables()
-    {
-        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);
-            }
-        }
-    }
-
-    /**
-     * Parse and analyze given SQL string
-     *
-     * @param $sql
-     * @return void
-     */
-    protected function parseAndAnalyzeSql($sql)
-    {
-        $parsedSql = $this->installerSql->getFieldDefinitions_fileContent($sql);
-        $this->analyzeFields($parsedSql);
-    }
-
-    /**
-     * Returns all field information gathered during
-     * analyzing all tables and fields.
-     *
-     * @return array
-     */
-    protected function getCompleteFieldInformation()
-    {
-        return ['incFields' => $this->cache_autoIncFields, 'fieldTypes' => $this->cache_fieldType, 'primaryKeys' => $this->cache_primaryKeys];
-    }
-
-    /**
-     * Creates a PHP code representation of the array that can be cached
-     * in the PHP code cache.
-     *
-     * @param array $fieldInformation
-     * @return string
-     */
-    protected function getCacheableString(array $fieldInformation)
-    {
-        $cacheString = 'return ';
-        $cacheString .= var_export($fieldInformation, true);
-        $cacheString .= ';';
-        return $cacheString;
-    }
-
-    /**
-     * 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\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 => $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];
-                        if (isset($fdef['featureIndex']['DEFAULT']['value'][1])) {
-                            $default = $fdef['featureIndex']['DEFAULT']['value'][1] . $default . $fdef['featureIndex']['DEFAULT']['value'][1];
-                        }
-                        $this->cache_fieldType[$table][$field]['default'] = $default;
-                    }
-                    if (isset($fdef['featureIndex']['AUTO_INCREMENT'])) {
-                        $this->cache_autoIncFields[$table] = $field;
-                    }
-                    if (isset($tdef['keys']['PRIMARY'])) {
-                        $this->cache_primaryKeys[$table] = substr($tdef['keys']['PRIMARY'], 13, -1);
-                    }
-                }
-            }
-        }
-    }
-
-    /**
-     * This function builds all definitions for mapped tables and fields
-     *
-     * @param array $fieldInfo
-     * @return array
-     *
-     * @see cacheFieldInfo()
-     */
-    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'])) {
-                    $mappedTableAlias = $mappedConf['mapTableName'];
-                    if (isset($mappedConf['mapFieldNames'][$fieldInfo['incFields'][$mappedTable]])) {
-                        $fieldInfo['incFields'][$mappedTableAlias] = $mappedConf['mapFieldNames'][$fieldInfo['incFields'][$mappedTable]];
-                    } else {
-                        $fieldInfo['incFields'][$mappedTableAlias] = $fieldInfo['incFields'][$mappedTable];
-                    }
-                }
-                if (array_key_exists($mappedTable, $fieldInfo['fieldTypes'])) {
-                    $tempMappedFieldConf = [];
-                    foreach ($fieldInfo['fieldTypes'][$mappedTable] as $field => $fieldConf) {
-                        $tempMappedFieldConf[$mappedConf['mapFieldNames'][$field]] = $fieldConf;
-                    }
-                    $fieldInfo['fieldTypes'][$mappedConf['mapTableName']] = $tempMappedFieldConf;
-                }
-                if (array_key_exists($mappedTable, $fieldInfo['primaryKeys'])) {
-                    $mappedTableAlias = $mappedConf['mapTableName'];
-                    if (isset($mappedConf['mapFieldNames'][$fieldInfo['primaryKeys'][$mappedTable]])) {
-                        $fieldInfo['primaryKeys'][$mappedTableAlias] = $mappedConf['mapFieldNames'][$fieldInfo['primaryKeys'][$mappedTable]];
-                    } else {
-                        $fieldInfo['primaryKeys'][$mappedTableAlias] = $fieldInfo['primaryKeys'][$mappedTable];
-                    }
-                }
-            }
-        }
-        return $fieldInfo;
-    }
-
-    /************************************
-     *
-     * Query Building (Overriding parent methods)
-     * 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().
-     */
-
-    /**
-     * 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 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 = false)
-    {
-        $pt = $this->debug ? GeneralUtility::milliseconds() : 0;
-        // Do field mapping if needed:
-        $ORIG_tableName = $table;
-        if ($tableArray = $this->map_needMapping($table)) {
-            // Field mapping of array:
-            $fields_values = $this->map_assocArray($fields_values, $tableArray);
-            // Table name:
-            if ($this->mapping[$table]['mapTableName']) {
-                $table = $this->mapping[$table]['mapTableName'];
-            }
-        }
-        // Select API:
-        $this->lastHandlerKey = $this->handler_getFromTableList($table);
-        $hType = (string)$this->handlerCfg[$this->lastHandlerKey]['type'];
-        $sqlResult = null;
-        switch ($hType) {
-            case 'native':
-                $this->lastQuery = $this->INSERTquery($table, $fields_values, $no_quote_fields);
-                if (is_string($this->lastQuery)) {
-                    $sqlResult = $this->query($this->lastQuery);
-                } else {
-                    $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);
-                    }
-                }
-                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]]) && !$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
-                        $fields_values[$this->cache_autoIncFields[$table]] = $this->handlerInstance[$this->lastHandlerKey]->GenID($table . '_' . $this->cache_autoIncFields[$table], $this->handlerInstance[$this->lastHandlerKey]->sequenceStart);
-                    }
-                }
-                $this->lastQuery = $this->INSERTquery($table, $fields_values, $no_quote_fields);
-                if (is_string($this->lastQuery)) {
-                    $sqlResult = $this->handlerInstance[$this->lastHandlerKey]->_query($this->lastQuery, false);
-                    $this->updateLastInsertId($table, $fields_values);
-                } else {
-                    $this->handlerInstance[$this->lastHandlerKey]->StartTrans();
-                    if ((string)$this->lastQuery[0] !== '') {
-                        $sqlResult = $this->handlerInstance[$this->lastHandlerKey]->_query($this->lastQuery[0], false);
-                        $new_id = $this->updateLastInsertId($table, $fields_values);
-                    }
-                    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 (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);
-                            }
-                        }
-                    }
-                    $this->handlerInstance[$this->lastHandlerKey]->CompleteTrans();
-                }
-                break;
-            case 'userdefined':
-                $sqlResult = $this->handlerInstance[$this->lastHandlerKey]->exec_INSERTquery($table, $fields_values, $no_quote_fields);
-                break;
-        }
-        if ($this->printErrors && $this->sql_error()) {
-            debug([$this->lastQuery, $this->sql_error()]);
-        }
-        if ($this->debug) {
-            $this->debugHandler('exec_INSERTquery', GeneralUtility::milliseconds() - $pt, [
-                'handlerType' => $hType,
-                'args' => [$table, $fields_values],
-                'ORIG_tablename' => $ORIG_tableName
-            ]);
-        }
-        foreach ($this->postProcessHookObjects as $hookObject) {
-            $hookObject->exec_INSERTquery_postProcessAction($table, $fields_values, $no_quote_fields, $this);
-        }
-        // Return output:
-        return $sqlResult;
-    }
-
-    /**
-     * Creates and executes an INSERT SQL-statement for $table with multiple rows.
-     *
-     * @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)
-    {
-        $res = null;
-        if ((string)$this->handlerCfg[$this->lastHandlerKey]['type'] === 'native') {
-            $this->lastHandlerKey = $this->handler_getFromTableList($table);
-            $res = $this->query(parent::INSERTmultipleRows($table, $fields, $rows, $no_quote_fields));
-        } else {
-            foreach ($rows as $row) {
-                $fields_values = [];
-                foreach ($fields as $key => $value) {
-                    $fields_values[$value] = $row[$key];
-                }
-                $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);
-        }
-        return $res;
-    }
-
-    /**
-     * 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 $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 = false)
-    {
-        $pt = $this->debug ? GeneralUtility::milliseconds() : 0;
-        // Do table/field mapping:
-        $ORIG_tableName = $table;
-        if ($tableArray = $this->map_needMapping($table)) {
-            // Field mapping of array:
-            $fields_values = $this->map_assocArray($fields_values, $tableArray);
-            // Where clause table and field mapping:
-            $whereParts = $this->SQLparser->parseWhereClause($where);
-            $this->map_sqlParts($whereParts, $tableArray[0]['table']);
-            $where = $this->SQLparser->compileWhereClause($whereParts, false);
-            // Table name:
-            if ($this->mapping[$table]['mapTableName']) {
-                $table = $this->mapping[$table]['mapTableName'];
-            }
-        }
-        // Select API
-        $this->lastHandlerKey = $this->handler_getFromTableList($table);
-        $hType = (string)$this->handlerCfg[$this->lastHandlerKey]['type'];
-        $sqlResult = null;
-        switch ($hType) {
-            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) {
-                        $stmt = 'UPDATE ' . $this->quoteFromTables($table) . ' SET ' . $this->quoteFromTables($field) . '=' . $this->fullQuoteStr($content, $table, true) . ' WHERE ' . $this->quoteWhereClause($where);
-                        $this->query($stmt);
-                    }
-                }
-                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();
-                }
-                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([$this->lastQuery, $this->sql_error()]);
-        }
-        if ($this->debug) {
-            $this->debugHandler('exec_UPDATEquery', GeneralUtility::milliseconds() - $pt, [
-                'handlerType' => $hType,
-                'args' => [$table, $where, $fields_values],
-                'ORIG_from_table' => $ORIG_tableName
-            ]);
-        }
-        foreach ($this->postProcessHookObjects as $hookObject) {
-            $hookObject->exec_UPDATEquery_postProcessAction($table, $where, $fields_values, $no_quote_fields, $this);
-        }
-        // Return result:
-        return $sqlResult;
-    }
-
-    /**
-     * Creates and executes a DELETE SQL-statement for $table where $where-clause
-     *
-     * @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)
-    {
-        $pt = $this->debug ? GeneralUtility::milliseconds() : 0;
-        // Do table/field mapping:
-        $ORIG_tableName = $table;
-        if ($tableArray = $this->map_needMapping($table)) {
-            // Where clause:
-            $whereParts = $this->SQLparser->parseWhereClause($where);
-            $this->map_sqlParts($whereParts, $tableArray[0]['table']);
-            $where = $this->SQLparser->compileWhereClause($whereParts, false);
-            // Table name:
-            if ($this->mapping[$table]['mapTableName']) {
-                $table = $this->mapping[$table]['mapTableName'];
-            }
-        }
-        // Select API
-        $this->lastHandlerKey = $this->handler_getFromTableList($table);
-        $hType = (string)$this->handlerCfg[$this->lastHandlerKey]['type'];
-        $sqlResult = null;
-        switch ($hType) {
-            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([$this->lastQuery, $this->sql_error()]);
-        }
-        if ($this->debug) {
-            $this->debugHandler('exec_DELETEquery', GeneralUtility::milliseconds() - $pt, [
-                'handlerType' => $hType,
-                'args' => [$table, $where],
-                'ORIG_from_table' => $ORIG_tableName
-            ]);
-        }
-        foreach ($this->postProcessHookObjects as $hookObject) {
-            $hookObject->exec_DELETEquery_postProcessAction($table, $where, $this);
-        }
-        // Return result:
-        return $sqlResult;
-    }
-
-    /**
-     * 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 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 = '')
-    {
-        $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:
-        $parsedFromTable = [];
-        $remappedParameters = [];
-        if ($tableArray = $this->map_needMapping($ORIG_tableName, false, $parsedFromTable)) {
-            $from = $parsedFromTable ? $parsedFromTable : $from_table;
-            $remappedParameters = $this->map_remapSELECTQueryParts($select_fields, $from, $where_clause, $groupBy, $orderBy);
-        }
-        // Get handler key and select API:
-        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'];
-        $sqlResult = null;
-        switch ($hType) {
-            case 'native':
-                if (!empty($remappedParameters)) {
-                    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 = $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 {
-                    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);
-                }
-                if (!is_object($sqlResult)) {
-                    throw new \RuntimeException('ADOdb could not run this query: ' . $this->lastQuery, 1421053336);
-                }
-                $sqlResult->TYPO3_DBAL_handlerType = 'adodb';
-                // Setting handler type in result object (for later recognition!)
-                $sqlResult->TYPO3_DBAL_tableList = $ORIG_tableName;
-                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([$this->lastQuery, $this->sql_error()]);
-        }
-        if ($this->debug) {
-            $data = [
-                'handlerType' => $hType,
-                'args' => [$from_table, $select_fields, $where_clause, $groupBy, $orderBy, $limit],
-                'ORIG_from_table' => $ORIG_tableName
-            ];
-            if ($this->conf['debugOptions']['numberRows']) {
-                $data['numberRows'] = $this->sql_num_rows($sqlResult);
-            }
-            $this->debugHandler('exec_SELECTquery', GeneralUtility::milliseconds() - $pt, $data);
-        }
-        // Return handler.
-        return $sqlResult;
-    }
-
-    /**
-     * Truncates a table.
-     *
-     * @param string $table Database tablename
-     * @return mixed Result from handler
-     */
-    public function exec_TRUNCATEquery($table)
-    {
-        $pt = $this->debug ? GeneralUtility::milliseconds() : 0;
-        // Do table/field mapping:
-        $ORIG_tableName = $table;
-        if ($tableArray = $this->map_needMapping($table)) {
-            // Table name:
-            if ($this->mapping[$table]['mapTableName']) {
-                $table = $this->mapping[$table]['mapTableName'];
-            }
-        }
-        // Select API
-        $this->lastHandlerKey = $this->handler_getFromTableList($table);
-        $hType = (string)$this->handlerCfg[$this->lastHandlerKey]['type'];
-        $sqlResult = null;
-        switch ($hType) {
-            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([$this->lastQuery, $this->sql_error()]);
-        }
-        if ($this->debug) {
-            $this->debugHandler('exec_TRUNCATEquery', GeneralUtility::milliseconds() - $pt, [
-                'handlerType' => $hType,
-                'args' => [$table],
-                'ORIG_from_table' => $ORIG_tableName
-            ]);
-        }
-        foreach ($this->postProcessHookObjects as $hookObject) {
-            $hookObject->exec_TRUNCATEquery_postProcessAction($table, $this);
-        }
-        // Return result:
-        return $sqlResult;
-    }
-
-    /**
-     * Executes a query.
-     * EXPERIMENTAL since TYPO3 4.4.
-     *
-     * @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 = [];
-                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 = [];
-                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);
-    }
-
-    /**************************************
-     *
-     * Query building
-     *
-     **************************************/
-    /**
-     * Creates an INSERT SQL-statement for $table from the array with field/value pairs $fields_values.
-     *
-     * @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 = 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) || 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 = [];
-        }
-        $blobFields = $clobFields = [];
-        $nArr = [];
-        $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 (!empty($blobFields) || !empty($clobFields)) {
-            $query = [];
-            if (!empty($nArr)) {
-                $query[0] = 'INSERT INTO ' . $this->quoteFromTables($table) . '
-                               (
-                                       ' . implode(',
-                                       ', array_keys($nArr)) . '
-                               ) VALUES (
-                                       ' . implode(',
-                                       ', $nArr) . '
-                               )';
-            }
-            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.
-     *
-     * @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') {
-            return parent::INSERTmultipleRows($table, $fields, $rows, $no_quote_fields);
-        }
-        $result = [];
-        foreach ($rows as $row) {
-            $fields_values = [];
-            foreach ($fields as $key => $value) {
-                $fields_values[$value] = $row[$key];
-            }
-            $rowQuery = $this->INSERTquery($table, $fields_values, $no_quote_fields);
-            if (is_array($rowQuery)) {
-                $result[] = $rowQuery;
-            } else {
-                $result[][0] = $rowQuery;
-            }
-        }
-        return $result;
-    }
-
-    /**
-     * Creates an UPDATE SQL-statement for $table where $where-clause (typ. 'uid=...') from the array with field/value pairs $fields_values.
-     *
-     *
-     * @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 = 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);
-            }
-            $blobFields = $clobFields = [];
-            $nArr = [];
-            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 = [];
-                }
-                $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;
-                    } 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;
-                    } else {
-                        // Add slashes old-school:
-                        // cast numeric 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 (!empty($blobFields) || !empty($clobFields)) {
-                $query = [];
-                if (!empty($nArr)) {
-                    $query[0] = 'UPDATE ' . $this->quoteFromTables($table) . '
-                                               SET
-                                                       ' . implode(',
-                                                       ', $nArr) . ($where !== '' ? '
-                                               WHERE
-                                                       ' . $this->quoteWhereClause($where) : '');
-                }
-                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 = 'UPDATE ' . $this->quoteFromTables($table) . '
-                                       SET
-                                               ' . implode(',
-                                               ', $nArr) . ($where !== '' ? '
-                                       WHERE
-                                               ' . $this->quoteWhereClause($where) : '');
-                if ($this->debugOutput || $this->store_lastBuiltQuery) {
-                    $this->debug_lastBuiltQuery = $query;
-                }
-            }
-            return $query;
-        } else {
-            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
-     *
-     * @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)) {
-            foreach ($this->preProcessHookObjects as $hookObject) {
-                $hookObject->DELETEquery_preProcessAction($table, $where, $this);
-            }
-            $table = $this->quoteFromTables($table);
-            $where = $this->quoteWhereClause($where);
-            $query = 'DELETE FROM ' . $table . ($where !== '' ? ' WHERE ' . $where : '');
-            if ($this->debugOutput || $this->store_lastBuiltQuery) {
-                $this->debug_lastBuiltQuery = $query;
-            }
-            return $query;
-        } else {
-            throw new \InvalidArgumentException('TYPO3 Fatal Error: "Where" clause argument for DELETE query was not a string in $this->DELETEquery() !', 1310027383);
-        }
-    }
-
-    /**
-     * Creates a SELECT SQL-statement
-     *
-     * @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'];
-        if ($hType === 'adodb' && $this->runningADOdbDriver('postgres')) {
-            // Possibly rewrite the LIMIT to be PostgreSQL-compatible
-            $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];
-                $limit = $numrows . ' OFFSET ' . $offset;
-            }
-        }
-        $select_fields = $this->quoteFieldNames($select_fields);
-        $from_table = $this->quoteFromTables($from_table);
-        $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) {
-            $this->debug_lastBuiltQuery = $query;
-        }
-        return $query;
-    }
-
-    /**
-     * Creates a SELECT SQL-statement to be used with an ADOdb backend.
-     *
-     * @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
-        $params[0] = $this->_quoteFieldNames($params[0]);
-        // $from_table
-        $params[1] = $this->_quoteFromTables($params[1]);
-        // $where_clause
-        if (!empty($params[2])) {
-            $params[2] = $this->_quoteWhereClause($params[2]);
-        }
-        // $group_by
-        if (!empty($params[3])) {
-            $params[3] = $this->_quoteGroupBy($params[3]);
-        }
-        // $order_by
-        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) {
-            $this->debug_lastBuiltQuery = $query;
-        }
-        return $query;
-    }
-
-    /**
-     * Compiles and returns an array of SELECTquery parameters (without $limit) to
-     * be used with SELECTquery() or exec_SELECTquery().
-     *
-     * @param array $params
-     * @return array array($select_fields, $from_table, $where_clause, $groupBy, $orderBy)
-     */
-    protected function compileSelectParameters(array $params)
-    {
-        $select_fields = $this->SQLparser->compileFieldList($params[0]);
-        $from_table = $this->SQLparser->compileFromTables($params[1]);
-        $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 [$select_fields, $from_table, $where_clause, $groupBy, $orderBy];
-    }
-
-    /**
-     * Creates a TRUNCATE TABLE SQL-statement
-     *
-     * @param string $table See exec_TRUNCATEquery()
-     * @return string Full SQL query for TRUNCATE TABLE
-     */
-    public function TRUNCATEquery($table)
-    {
-        foreach ($this->preProcessHookObjects as $hookObject) {
-            $hookObject->TRUNCATEquery_preProcessAction($table, $this);
-        }
-        $table = $this->quoteFromTables($table);
-        // Build actual query
-        $query = 'TRUNCATE TABLE ' . $table;
-        if ($this->debugOutput || $this->store_lastBuiltQuery) {
-            $this->debug_lastBuiltQuery = $query;
-        }
-        return $query;
-    }
-
-    /**************************************
-     *
-     * Prepared Query Support
-     *
-     **************************************/
-    /**
-     * Creates a SELECT prepared SQL statement.
-     *
-     * @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 = [])
-    {
-        $pt = $this->debug ? GeneralUtility::milliseconds() : 0;
-        $precompiledParts = [];
-        if ($this->queryCache) {
-            $cacheKey = 'prepare_SELECTquery-' . \TYPO3\CMS\Dbal\QueryCache::getCacheKey([
-                'selectFields' => $select_fields,
-                'fromTable' => $from_table,
-                'whereClause' => $where_clause,
-                'groupBy' => $groupBy,
-                'orderBy' => $orderBy,
-                'limit' => $limit
-            ]);
-            if ($this->queryCache->has($cacheKey)) {
-                $precompiledParts = $this->queryCache->get($cacheKey);
-                if ($this->debug) {
-                    $data = [
-                        'args' => [$from_table, $select_fields, $where_clause, $groupBy, $orderBy, $limit, $input_parameters],
-                        'precompiledParts' => $precompiledParts
-                    ];
-                    $this->debugHandler('prepare_SELECTquery (cache hit)', GeneralUtility::milliseconds() - $pt, $data);
-                }
-            }
-        }
-        $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:
-            $parsedFromTable = [];
-            $queryComponents = [];
-            if ($tableArray = $this->map_needMapping($ORIG_tableName, false, $parsedFromTable)) {
-                $from = $parsedFromTable ? $parsedFromTable : $from_table;
-                $components = $this->map_remapSELECTQueryParts($select_fields, $from, $where_clause, $groupBy, $orderBy);
-                $queryComponents['SELECT'] = $components[0];
-                $queryComponents['FROM'] = $components[1];
-                $queryComponents['WHERE'] = $components[2];
-                $queryComponents['GROUPBY'] = $components[3];
-                $queryComponents['ORDERBY'] = $components[4];
-                $queryComponents['parameters'] = $components[5];
-            } else {
-                $queryComponents = $this->getQueryComponents($select_fields, $from_table, $where_clause, $groupBy, $orderBy, $limit);
-            }
-            $queryComponents['ORIG_tableName'] = $ORIG_tableName;
-            if (!$this->runningNative()) {
-                // Quotes all fields
-                $queryComponents['SELECT'] = $this->_quoteFieldNames($queryComponents['SELECT']);
-                $queryComponents['FROM'] = $this->_quoteFromTables($queryComponents['FROM']);
-                $queryComponents['WHERE'] = $this->_quoteWhereClause($queryComponents['WHERE']);
-                $queryComponents['GROUPBY'] = $this->_quoteGroupBy($queryComponents['GROUPBY']);
-                $queryComponents['ORDERBY'] = $this->_quoteOrderBy($queryComponents['ORDERBY']);
-            }
-            $precompiledParts = $this->precompileSELECTquery($queryComponents);
-            if ($this->queryCache) {
-                try {
-                    $this->queryCache->set($cacheKey, $precompiledParts);
-                } catch (\TYPO3\CMS\Core\Cache\Exception $e) {
-                    if ($this->debug) {
-                        GeneralUtility::devLog($e->getMessage(), 'dbal', 1);
-                    }
-                }
-            }
-        }
-        $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) {
-            $preparedStatement->bindValue($key, $value, \TYPO3\CMS\Core\Database\PreparedStatement::PARAM_AUTOTYPE);
-        }
-        if ($this->debug) {
-            $data = [
-                'args' => [$from_table, $select_fields, $where_clause, $groupBy, $orderBy, $limit, $input_parameters],
-                'ORIG_from_table' => $ORIG_tableName
-            ];
-            $this->debugHandler('prepare_SELECTquery', GeneralUtility::milliseconds() - $pt, $data);
-        }
-        // Return prepared statement
-        return $preparedStatement;
-    }
-
-    /**
-     * Returns the parsed query components.
-     *
-     * @param string $select_fields
-     * @param string $from_table
-     * @param string $where_clause
-     * @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)
-    {
-        $queryComponents = [
-            'SELECT' => '',
-            'FROM' => '',
-            'WHERE' => '',
-            'GROUPBY' => '',
-            'ORDERBY' => '',
-            'LIMIT' => '',
-            'parameters' => []
-        ];
-        $this->lastHandlerKey = $this->handler_getFromTableList($from_table);
-        $hType = (string)$this->handlerCfg[$this->lastHandlerKey]['type'];
-        if ($hType === 'adodb' && $this->runningADOdbDriver('postgres')) {
-            // Possibly rewrite the LIMIT to be PostgreSQL-compatible
-            $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];
-                $limit = $numrows . ' OFFSET ' . $offset;
-            }
-        }
-        $queryComponents['LIMIT'] = $limit;
-        $queryComponents['SELECT'] = $this->SQLparser->parseFieldList($select_fields);
-        if ($this->SQLparser->parse_error) {
-            throw new \InvalidArgumentException($this->SQLparser->parse_error, 1310027408);
-        }
-        $queryComponents['FROM'] = $this->SQLparser->parseFromTables($from_table);
-        $queryComponents['WHERE'] = $this->SQLparser->parseWhereClause($where_clause, '', $queryComponents['parameters']);
-        if (!is_array($queryComponents['WHERE'])) {
-            throw new \InvalidArgumentException('Could not parse where clause', 1310027427);
-        }
-        $queryComponents['GROUPBY'] = $this->SQLparser->parseFieldList($groupBy);
-        $queryComponents['ORDERBY'] = $this->SQLparser->parseFieldList($orderBy);
-        // Return the query components
-        return $queryComponents;
-    }
-
-    /**
-     * Precompiles a SELECT prepared SQL statement.
-     *
-     * @param array $components
-     * @return array Precompiled SQL statement
-     */
-    protected function precompileSELECTquery(array $components)
-    {
-        $parameterWrap = '__' . dechex(time()) . '__';
-        foreach ($components['parameters'] as $key => $params) {
-            if ($key === '?') {
-                foreach ($params as $index => $param) {
-                    $components['parameters'][$key][$index][0] = $parameterWrap . $param[0] . $parameterWrap;
-                }
-            } else {
-                $components['parameters'][$key][0] = $parameterWrap . $params[0] . $parameterWrap;
-            }
-        }
-        $select_fields = $this->SQLparser->compileFieldList($components['SELECT']);
-        $from_table = $this->SQLparser->compileFromTables($components['FROM']);
-        $where_clause = $this->SQLparser->compileWhereClause($components['WHERE']);
-        $groupBy = $this->SQLparser->compileFieldList($components['GROUPBY']);
-        $orderBy = $this->SQLparser->compileFieldList($components['ORDERBY']);
-        $limit = $components['LIMIT'];
-        $precompiledParts = [];
-        $this->lastHandlerKey = $this->handler_getFromTableList($components['ORIG_tableName']);
-        $hType = (string)$this->handlerCfg[$this->lastHandlerKey]['type'];
-        $precompiledParts['handler'] = $hType;
-        $precompiledParts['ORIG_tableName'] = $components['ORIG_tableName'];
-        switch ($hType) {
-            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'] = [
-                    'SELECT' => $select_fields,
-                    'FROM' => $from_table,
-                    'WHERE' => $where_clause,
-                    'GROUPBY' => $groupBy,
-                    'ORDERBY' => $orderBy,
-                    'LIMIT' => $limit
-                ];
-                break;
-        }
-        return $precompiledParts;
-    }
-
-    /**
-     * Prepares a prepared query.
-     *
-     * @param string $query The query to execute
-     * @param array $queryComponents The components of the query to execute
-     * @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 prepare_PREPAREDquery($query, array $queryComponents)
-    {
-        $pt = $this->debug ? GeneralUtility::milliseconds() : 0;
-        // Get handler key and select API:
-        $preparedStatement = null;
-        switch ($queryComponents['handler']) {
-            case 'native':
-                $this->lastQuery = $query;
-                $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([$this->lastQuery, $this->sql_error()]);
-        }
-        if ($this->debug) {
-            $data = [
-                'handlerType' => $queryComponents['handler'],
-                'args' => $queryComponents,
-                'ORIG_from_table' => $queryComponents['ORIG_tableName']
-            ];
-            $this->debugHandler('prepare_PREPAREDquery', GeneralUtility::milliseconds() - $pt, $data);
-        }
-        // Return result handler.
-        return $preparedStatement;
-    }
-
-    /**************************************
-     *
-     * Functions for quoting table/field names
-     *
-     **************************************/
-    /**
-     * Quotes components of a SELECT subquery.
-     *
-     * @param array $components        Array of SQL query components
-     * @return array
-     */
-    protected function quoteSELECTsubquery(array $components)
-    {
-        $components['SELECT'] = $this->_quoteFieldNames($components['SELECT']);
-        $components['FROM'] = $this->_quoteFromTables($components['FROM']);
-        $components['WHERE'] = $this->_quoteWhereClause($components['WHERE']);
-        return $components;
-    }
-
-    /**
-     * Quotes field (and table) names with the quote character suitable for the DB being used
-     *
-     * @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 == '') {
-            return '';
-        }
-        if ($this->runningNative()) {
-            return $select_fields;
-        }
-        $select_fields = $this->SQLparser->parseFieldList($select_fields);
-        if ($this->SQLparser->parse_error) {
-            throw new \InvalidArgumentException($this->SQLparser->parse_error, 1310027490);
-        }
-        $select_fields = $this->_quoteFieldNames($select_fields);
-        return $this->SQLparser->compileFieldList($select_fields);
-    }
-
-    /**
-     * 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
-     * @see quoteFieldNames()
-     */
-    protected function _quoteFieldNames(array $select_fields)
-    {
-        foreach ($select_fields as $k => $v) {
-            if ($select_fields[$k]['field'] != '' && $select_fields[$k]['field'] != '*' && !is_numeric($select_fields[$k]['field'])) {
-                $select_fields[$k]['field'] = $this->quoteName($select_fields[$k]['field']);
-            }
-            if ($select_fields[$k]['table'] != '' && !is_numeric($select_fields[$k]['table'])) {
-                $select_fields[$k]['table'] = $this->quoteName($select_fields[$k]['table']);
-            }
-            if ($select_fields[$k]['as'] != '') {
-                $select_fields[$k]['as'] = $this->quoteName($select_fields[$k]['as']);
-            }
-            if (isset($select_fields[$k]['func_content.']) && $select_fields[$k]['func_content.'][0]['func_content'] != '*') {
-                $select_fields[$k]['func_content.'][0]['func_content'] = $this->quoteFieldNames($select_fields[$k]['func_content.'][0]['func_content']);
-                $select_fields[$k]['func_content'] = $this->quoteFieldNames($select_fields[$k]['func_content']);
-            }
-            if (isset($select_fields[$k]['flow-control'])) {
-                // Quoting flow-control statements
-                if ($select_fields[$k]['flow-control']['type'] === 'CASE') {
-                    if (isset($select_fields[$k]['flow-control']['case_field'])) {
-                        $select_fields[$k]['flow-control']['case_field'] = $this->quoteFieldNames($select_fields[$k]['flow-control']['case_field']);
-                    }
-                    foreach ($select_fields[$k]['flow-control']['when'] as $key => $when) {
-                        $select_fields[$k]['flow-control']['when'][$key]['when_value'] = $this->_quoteWhereClause($when['when_value']);
-                    }
-                }
-            }
-        }
-        return $select_fields;
-    }
-
-    /**
-     * Quotes table names with the quote character suitable for the DB being used
-     *
-     * @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 === '') {
-            return '';
-        }
-        if ($this->runningNative()) {
-            return $from_table;
-        }
-        $from_table = $this->SQLparser->parseFromTables($from_table);
-        $from_table = $this->_quoteFromTables($from_table);
-        return $this->SQLparser->compileFromTables($from_table);
-    }
-
-    /**
-     * Quotes table names in a SQL FROM clause according to DB rules
-     *
-     * @param array $from_table The parsed FROM clause to quote
-     * @return array
-     * @see quoteFromTables()
-     */
-    protected function _quoteFromTables(array $from_table)
-    {
-        foreach ($from_table as $k => $v) {
-            $from_table[$k]['table'] = $this->quoteName($from_table[$k]['table']);
-            if ($from_table[$k]['as'] != '') {
-                $from_table[$k]['as'] = $this->quoteName($from_table[$k]['as']);
-            }
-            if (is_array($v['JOIN'])) {
-                foreach ($v['JOIN'] as $joinCnt => $join) {
-                    $from_table[$k]['JOIN'][$joinCnt]['withTable'] = $this->quoteName($join['withTable']);
-                    $from_table[$k]['JOIN'][$joinCnt]['as'] = $join['as'] ? $this->quoteName($join['as']) : '';
-                    foreach ($from_table[$k]['JOIN'][$joinCnt]['ON'] as &$condition) {
-                        $condition['left']['table'] = $condition['left']['table'] ? $this->quoteName($condition['left']['table']) : '';
-                        $condition['left']['field'] = $this->quoteName($condition['left']['field']);
-                        $condition['right']['table'] = $condition['right']['table'] ? $this->quoteName($condition['right']['table']) : '';
-                        $condition['right']['field'] = $this->quoteName($condition['right']['field']);
-                    }
-                }
-            }
-        }
-        return $from_table;
-    }
-
-    /**
-     * Quotes the field (and table) names within a where clause with the quote character suitable for the DB being used
-     *
-     * @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()) {
-            return $where_clause;
-        }
-        $where_clause = $this->SQLparser->parseWhereClause($where_clause);
-        if (is_array($where_clause)) {
-            $where_clause = $this->_quoteWhereClause($where_clause);
-            $where_clause = $this->SQLparser->compileWhereClause($where_clause);
-        } else {
-            throw new \InvalidArgumentException('Could not parse where clause', 1310027511);
-        }
-        return $where_clause;
-    }
-
-    /**
-     * Quotes field names in a SQL WHERE clause according to DB rules
-     *
-     * @param array $where_clause The parsed WHERE clause to quote
-     * @return array
-     * @see quoteWhereClause()
-     */
-    protected function _quoteWhereClause(array $where_clause)
-    {
-        foreach ($where_clause as $k => $v) {
-            // Look for sublevel:
-            if (is_array($where_clause[$k]['sub'])) {
-                $where_clause[$k]['sub'] = $this->_quoteWhereClause($where_clause[$k]['sub']);
-            } elseif (isset($v['func'])) {
-                switch ($where_clause[$k]['func']['type']) {
-                    case 'EXISTS':
-                        $where_clause[$k]['func']['subquery'] = $this->quoteSELECTsubquery($v['func']['subquery']);
-                        break;
-                    case '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'] !== '') {
-                            if ($this->dbmsSpecifics->getSpecific(Specifics\AbstractSpecifics::CAST_FIND_IN_SET)) {
-                                $where_clause[$k]['func']['table'] = 'CAST(' . $this->quoteName($v['func']['table']);
-                            } else {
-                                $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)) {
-                                if ($where_clause[$k]['func']['table'] !== '') {
-                                    $where_clause[$k]['func']['field'] = $this->quoteName($v['func']['field']) . ' AS CHAR)';
-                                } else {
-                                    $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 'CAST':
-                        // Intentional fallthrough
-                    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'] != '') {
-                    $where_clause[$k]['table'] = $this->quoteName($where_clause[$k]['table']);
-                }
-                if (!is_numeric($where_clause[$k]['field'])) {
-                    $where_clause[$k]['field'] = $this->quoteName($where_clause[$k]['field']);
-                }
-                if (isset($where_clause[$k]['calc_table'])) {
-                    if ($where_clause[$k]['calc_table'] != '') {
-                        $where_clause[$k]['calc_table'] = $this->quoteName($where_clause[$k]['calc_table']);
-                    }
-                    if ($where_clause[$k]['calc_field'] != '') {
-                        $where_clause[$k]['calc_field'] = $this->quoteName($where_clause[$k]['calc_field']);
-                    }
-                }
-            }
-            if ($where_clause[$k]['comparator']) {
-                if (isset($v['value']['operator'])) {
-                    foreach ($where_clause[$k]['value']['args'] as $argK => $fieldDef) {
-                        $where_clause[$k]['value']['args'][$argK]['table'] = $this->quoteName($fieldDef['table']);
-                        $where_clause[$k]['value']['args'][$argK]['field'] = $this->quoteName($fieldDef['field']);
-                    }
-                } else {
-                    // Detecting value type; list or plain:
-                    $comparator = $this->SQLparser->normalizeKeyword($where_clause[$k]['comparator']);
-                    if ($comparator === 'NOTIN' || $comparator === 'IN') {
-                        if (isset($v['subquery'])) {
-                            $where_clause[$k]['subquery'] = $this->quoteSELECTsubquery($v['subquery']);
-                        }
-                    } else {
-                        if (
-                            (!isset($where_clause[$k]['value'][1]) || $where_clause[$k]['value'][1] == '')
-                            && is_string($where_clause[$k]['value'][0]) && strstr($where_clause[$k]['value'][0], '.')
-                        ) {
-                            $where_clause[$k]['value'][0] = $this->quoteFieldNames($where_clause[$k]['value'][0]);
-                        } elseif ($this->runningADOdbDriver('mssql')) {
-                            $where_clause[$k]['value'][0] = substr($this->handlerInstance[$this->lastHandlerKey]->qstr($where_clause[$k]['value'][0]), 1, -1);
-                        }
-                    }
-                }
-            }
-        }
-        return $where_clause;
-    }
-
-    /**
-     * Quotes the field (and table) names within a group by clause with the quote
-     * character suitable for the DB being used
-     *
-     * @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 === '') {
-            return '';
-        }
-        if ($this->runningNative()) {
-            return $groupBy;
-        }
-        $groupBy = $this->SQLparser->parseFieldList($groupBy);
-        $groupBy = $this->_quoteGroupBy($groupBy);
-        return $this->SQLparser->compileFieldList($groupBy);
-    }
-
-    /**
-     * 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
-     * @see quoteGroupBy()
-     */
-    protected function _quoteGroupBy(array $groupBy)
-    {
-        foreach ($groupBy as $k => $v) {
-            $groupBy[$k]['field'] = $this->quoteName($groupBy[$k]['field']);
-            if ($groupBy[$k]['table'] != '') {
-                $groupBy[$k]['table'] = $this->quoteName($groupBy[$k]['table']);
-            }
-        }
-        return $groupBy;
-    }
-
-    /**
-     * Quotes the field (and table) names within an order by clause with the quote
-     * character suitable for the DB being used
-     *
-     * @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 === '') {
-            return '';
-        }
-        if ($this->runningNative()) {
-            return $orderBy;
-        }
-        $orderBy = $this->SQLparser->parseFieldList($orderBy);
-        $orderBy = $this->_quoteOrderBy($orderBy);
-        return $this->SQLparser->compileFieldList($orderBy);
-    }
-
-    /**
-     * Quotes field names in a SQL ORDER BY clause according to DB rules
-     *
-     * @param array $orderBy The parsed ORDER BY clause to quote
-     * @return         array
-     * @see quoteOrderBy()
-     */
-    protected function _quoteOrderBy(array $orderBy)
-    {
-        foreach ($orderBy as $k => $v) {
-            if ($orderBy[$k]['table'] === '' && $v['field'] !== '' && ctype_digit($v['field'])) {
-                continue;
-            }
-            $orderBy[$k]['field'] = $this->quoteName($orderBy[$k]['field']);
-            if ($orderBy[$k]['table'] !== '') {
-                $orderBy[$k]['table'] = $this->quoteName($orderBy[$k]['table']);
-            }
-        }
-        return $orderBy;
-    }
-
-    /**************************************
-     *
-     * Various helper functions
-     *
-     **************************************/
-    /**
-     * Escaping and quoting values for SQL statements.
-     *
-     * @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,  $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 $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->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 = 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 $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;
-        $useNameQuote = isset($this->handlerCfg[$handlerKey]['config']['useNameQuote']) ? $this->handlerCfg[$handlerKey]['config']['useNameQuote'] : false;
-        if ($useNameQuote) {
-            // Sometimes DataDictionary is not properly instantiated
-            if (!is_object($this->handlerInstance[$handlerKey]->DataDictionary)) {
-                $this->handlerInstance[$handlerKey]->DataDictionary = NewDataDictionary($this->handlerInstance[$handlerKey]);
-            }
-            return $this->handlerInstance[$handlerKey]->DataDictionary->NameQuote($name);
-        } else {
-            $quote = $useBackticks ? '`' : $this->handlerInstance[$handlerKey]->nameQuote;
-            return $quote . $name . $quote;
-        }
-    }
-
-    /**
-     * 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 (!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;
-    }
-
-    /**
-     * Update the id information for the last inserted record
-     *
-     * @param string $table
-     * @param array $fieldValues
-     * @return null|int
-     */
-    protected function updateLastInsertId($table, array $fieldValues)
-    {
-        if ($table === 'tx_dbal_debuglog') {
-            return null;
-        }
-        $newId = null;
-        if (isset($fieldValues[$this->cache_autoIncFields[$table]])) {
-            $newId = $fieldValues[$this->cache_autoIncFields[$table]];
-        } elseif ($this->handlerInstance[$this->lastHandlerKey]->hasInsertID && !empty($this->cache_autoIncFields[$table])) {
-            // The table is able to retrieve the ID of the last insert
-            $newId = $this->handlerInstance[$this->lastHandlerKey]->Insert_ID($table, $this->cache_autoIncFields[$table]);
-        }
-        if ($newId !== null) {
-            $this->handlerInstance[$this->lastHandlerKey]->last_insert_id = $newId;
-        }
-        return $newId;
-    }
-
-    /*********************************************
-     *
-     * 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;
-        }
-
-        $strippedIndexSQL = preg_replace_callback(
-            '/\A([^(]+)\((.*)\)\Z/',
-            function ($matches) {
-                return $matches[1] . '(' . preg_replace('/\((\d+)\)/', '', $matches[2]) . ')';
-            },
-            $indexSQL
-        );
-
-        return $strippedIndexSQL === null ? $indexSQL : $strippedIndexSQL;
-    }
-
-    /**
-     * 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 $fieldSQL
-     * @return string
-     */
-    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;
-    }
-
-    /**************************************
-     *
-     * SQL wrapper functions (Overriding parent methods)
-     * (For use in your applications)
-     *
-     **************************************/
-    /**
-     * Returns the error status on the last query() execution
-     *
-     * @return string MySQLi error string.
-     */
-    public function sql_error()
-    {
-        $output = '';
-        switch ($this->handlerCfg[$this->lastHandlerKey]['type']) {
-            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 last query() execution
-     *
-     * @return int MySQLi error number
-     */
-    public function sql_errno()
-    {
-        $output = 0;
-        switch ($this->handlerCfg[$this->lastHandlerKey]['type']) {
-            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;
-    }
-
-    /**
-     * Returns the number of selected 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 = $this->determineHandlerType($res);
-        $output = 0;
-        switch ($handlerType) {
-            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 bool|\mysqli_result|object $res MySQLi result object / DBAL object
-     * @return array|bool Associative array of result row.
-     */
-    public function sql_fetch_assoc($res)
-    {
-        $tableList = '';
-        $output = false;
-        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:
-                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]);
-                                }
-                            }
-                        }
-                    }
-                }
-                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)) {
-            if ($tables = $this->map_needMapping($tableList, true)) {
-                $output = $this->map_assocArray($output, $tables, 1);
-            }
-        }
-        if ($output === null) {
-            // Needed for compatibility
-            $output = false;
-        }
-        // Return result:
-        return $output;
-    }
-
-    /**
-     * 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 bool|\mysqli_result|object $res MySQLi result object / DBAL object
-     * @return array|bool Array with result rows.
-     */
-    public function sql_fetch_row($res)
-    {
-        $output = false;
-        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++;
-                            }
-                        }
-                    }
-                }
-                break;
-            case 'userdefined':
-                $output = $res->sql_fetch_row();
-                break;
-        }
-        if ($output === null) {
-            // Needed for compatibility
-            $output = false;
-        }
-        return $output;
-    }
-
-    /**
-     * Free result memory
-     * free_result() wrapper function
-     *
-     * @param bool|\mysqli_result|\ADORecordSet|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;
-        }
-        $output = true;
-        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);
-                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 int The uid of the last inserted record.
-     */
-    public function sql_insert_id()
-    {
-        $output = 0;
-        switch ($this->handlerCfg[$this->lastHandlerKey]['type']) {
-            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;
-    }
-
-    /**
-     * Returns the number of rows affected by the last INSERT, UPDATE or DELETE 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 = $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;
-    }
-
-    /**
-     * Move internal result pointer
-     *
-     * @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;
-        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;
-    }
-
-    /**
-     * Get the type of the specified field in a result
-     *
-     * If the first parameter is a string, it is used as table name for the lookup.
-     *
-     * @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['mapFieldNames'])) {
-                foreach ($tableMapInfo['mapFieldNames'] as $fieldName => $fieldMapInfo) {
-                    if ($fieldMapInfo === $field) {
-                        // Field name is mapped => use original name
-                        $field = $fieldName;
-                    }
-                }
-            }
-        }
-        return $this->cache_fieldType[$table][$field]['metaType'];
-    }
-
-    /**
-     * Get the type of the specified field in a result
-     * mysql_field_type() wrapper function
-     *
-     * @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) {
-            debug(['no res in sql_field_type!']);
-            return 'text';
-        } elseif (is_string($res)) {
-            if ($res === 'tx_dbal_debuglog') {
-                return 'text';
-            }
-            $handlerType = 'adodb';
-        } else {
-            $handlerType = $this->determineHandlerType($res);
-        }
-        $output = '';
-        switch ($handlerType) {
-            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;
-    }
-
-    /**********
-     *
-     * Legacy functions, bound to _DEFAULT handler. (Overriding parent methods)
-     * Deprecated or still experimental.
-     *
-     **********/
-    /**
-     * 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!
-     *
-     * 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 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'], ['allowed_classes' => false]);
-        if ($globalConfig['sql_query.']['passthrough']) {
-            return parent::sql_query($query);
-        }
-        // This method is heavily used by Extbase, try to handle it with DBAL-native methods
-        $queryParts = $this->SQLparser->parseSQL($query);
-        if (is_array($queryParts)) {
-            $operation = $queryParts['type'];
-            if ($operation === 'SELECT' || $operation === 'UPDATE' || $operation === 'INSERT' || $operation === 'DELETE') {
-                return $this->exec_query($queryParts);
-            }
-        }
-        $sqlResult = null;
-        switch ($this->handlerCfg['_DEFAULT']['type']) {
-            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()) {
-            debug([$this->lastQuery, $this->sql_error()]);
-        }
-        return $sqlResult;
-    }
-
-    /**
-     * Open a (persistent) connection to a MySQL server
-     *
-     * @return bool|void
-     */
-    public function sql_pconnect()
-    {
-        return $this->handler_init('_DEFAULT');
-    }
-
-    /**
-     * Select a SQL database
-     *
-     * @return bool Returns TRUE on success or FALSE on failure.
-     */
-    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;
-    }
-
-    /**************************************
-     *
-     * SQL admin functions
-     * (For use in the Install Tool and Extension Manager)
-     *
-     **************************************/
-    /**
-     * 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!
-     *
-     * @return array Each entry represents a database name
-     * @throws \RuntimeException
-     */
-    public function admin_get_dbs()
-    {
-        $dbArr = [];
-        $this->lastHandlerKey = '_DEFAULT';
-        switch ($this->handlerCfg['_DEFAULT']['type']) {
-            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;
-                    }
-                }
-                $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;
-        }
-        return $dbArr;
-    }
-
-    /**
-     * 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
-     *
-     * @return array Array with tablenames as key and arrays with status information as value
-     */
-    public function admin_get_tables()
-    {
-        $whichTables = [];
-        // Getting real list of tables:
-        switch ($this->handlerCfg['_DEFAULT']['type']) {
-            case 'native':
-                $tables_result = $this->query('SHOW TABLE STATUS FROM `' . $this->handlerCfg['_DEFAULT']['config']['database'] . '`');
-                if (!$this->sql_error()) {
-                    while ($theTable = $this->sql_fetch_assoc($tables_result)) {
-                        $whichTables[$theTable['Name']] = $theTable;
-                    }
-                }
-                $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] = ['Name' => $theTable];
-                    }
-                }
-                break;
-            case 'userdefined':
-                $whichTables = $this->handlerInstance['_DEFAULT']->admin_get_tables();
-                break;
-        }
-        // Check mapping:
-        if (is_array($this->mapping) && !empty($this->mapping)) {
-            // Mapping table names in reverse, first getting list of real table names:
-            $tMap = [];
-            foreach ($this->mapping as $tN => $tMapInfo) {
-                if (isset($tMapInfo['mapTableName'])) {
-                    $tMap[$tMapInfo['mapTableName']] = $tN;
-                }
-            }
-            // Do mapping:
-            $newList = [];
-            foreach ($whichTables as $tN => $tDefinition) {
-                if (isset($tMap[$tN])) {
-                    $tN = $tMap[$tN];
-                    $tDefinition = ['Name' => $tN];
-                }
-                $newList[$tN] = $tDefinition;
-            }
-            $whichTables = $newList;
-        }
-        // 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] = ['Name' => $key];
-            }
-        }
-        return $whichTables;
-    }
-
-    /**
-     * 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.
-     *
-     * @param string $tableName Table name
-     * @return array Field information in an associative array with fieldname => field row
-     */
-    public function admin_get_fields($tableName)
-    {
-        $output = [];
-        // Do field mapping if needed:
-        $ORIG_tableName = $tableName;
-        if ($tableArray = $this->map_needMapping($tableName)) {
-            // Table name:
-            if ($this->mapping[$tableName]['mapTableName']) {
-                $tableName = $this->mapping[$tableName]['mapTableName'];
-            }
-        }
-        // Find columns
-        $this->lastHandlerKey = $this->handler_getFromTableList($tableName);
-        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'])) {
-            $revFields = array_flip($this->mapping[$ORIG_tableName]['mapFieldNames']);
-            $newOutput = [];
-            foreach ($output as $fN => $fInfo) {
-                if (isset($revFields[$fN])) {
-                    $fN = $revFields[$fN];
-                    $fInfo['Field'] = $fN;
-                }
-                $newOutput[$fN] = $fInfo;
-            }
-            $output = $newOutput;
-        }
-        return $output;
-    }
-
-    /**
-     * 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 $tableName Table name
-     * @return array Key information in a numeric array
-     */
-    public function admin_get_keys($tableName)
-    {
-        $output = [];
-        // Do field mapping if needed:
-        $ORIG_tableName = $tableName;
-        if ($tableArray = $this->map_needMapping($tableName)) {
-            // Table name:
-            if ($this->mapping[$tableName]['mapTableName']) {
-                $tableName = $this->mapping[$tableName]['mapTableName'];
-            }
-        }
-        // Find columns
-        $this->lastHandlerKey = $this->handler_getFromTableList($tableName);
-        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 = [];
-                $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;
-        }
-        // mapping should be done:
-        if (is_array($tableArray) && is_array($this->mapping[$ORIG_tableName]['mapFieldNames'])) {
-            $revFields = array_flip($this->mapping[$ORIG_tableName]['mapFieldNames']);
-            $newOutput = [];
-            foreach ($output as $kN => $kInfo) {
-                // Table:
-                $kInfo['Table'] = $ORIG_tableName;
-                // Column
-                if (isset($revFields[$kInfo['Column_name']])) {
-                    $kInfo['Column_name'] = $revFields[$kInfo['Column_name']];
-                }
-                // Write it back:
-                $newOutput[$kN] = $kInfo;
-            }
-            $output = $newOutput;
-        }
-        return $output;
-    }
-
-    /**
-     * 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.
-     *
-     * 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()
-    {
-        $output = [];
-        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;
-    }
-
-    /**
-     * mysqli() wrapper function, used by the Install Tool and EM for all queries regarding management of the database!
-     *
-     * @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'];
-        // 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);
-                break;
-            case 'INSERT':
-
-            case 'TRUNCATETABLE':
-                $this->map_genericQueryParsed($parsedQuery);
-                break;
-            case 'CREATEDATABASE':
-                throw new \InvalidArgumentException('Creating a database with DBAL is not supported. Did you really read the manual?', 1310027716);
-                break;
-            default:
-                throw new \InvalidArgumentException('ERROR: Invalid Query type (' . $parsedQuery['type'] . ') for ->admin_query() function!: "' . htmlspecialchars($query) . '"', 1310027740);
-        }
-        // 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'], ['INSERT', 'DROPTABLE', 'ALTERTABLE'])) {
-                    $result = $this->query($compiledQuery);
-                } else {
-                    $result = $this->query($compiledQuery[0]);
-                }
-                break;
-            case 'adodb':
-                // Compiling query:
-                $compiledQuery = $this->SQLparser->compileSQL($this->lastParsedAndMappedQueryArray);
-                switch ($this->lastParsedAndMappedQueryArray['type']) {
-                    case 'INSERT':
-                        $result = $this->exec_INSERTquery($this->lastParsedAndMappedQueryArray['TABLE'], $compiledQuery);
-                        break;
-                    case 'TRUNCATETABLE':
-                        $result = $this->exec_TRUNCATEquery($this->lastParsedAndMappedQueryArray['TABLE']);
-                        break;
-                    default:
-                        if (!is_array($compiledQuery)) {
-                            $compiledQuery = [$compiledQuery];
-                        }
-                        $result = $this->handlerInstance[$this->lastHandlerKey]->DataDictionary->ExecuteSQLArray($compiledQuery);
-                }
-                break;
-            case 'userdefined':
-                // Compiling query:
-                $compiledQuery = $this->SQLparser->compileSQL($this->lastParsedAndMappedQueryArray);
-                $result = $this->handlerInstance[$this->lastHandlerKey]->admin_query($compiledQuery);
-            default:
-        }
-        return $result;
-    }
-
-    /************************************
-     *
-     * Handler management
-     *
-     **************************************/
-    /**
-     * 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!)
-     *
-     * @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;
-        if (!isset($this->cache_handlerKeyFromTableList[$key])) {
-            // Get tables separated:
-            $_tableList = $tableList;
-            $tableArray = $this->SQLparser->parseFromTables($_tableList);
-            // If success, traverse the tables:
-            if (is_array($tableArray) && !empty($tableArray)) {
-                $outputHandlerKey = '';
-                foreach ($tableArray as $vArray) {
-                    // Find handler key, select "_DEFAULT" if none is specifically configured:
-                    $handlerKey = $this->table2handlerKeys[$vArray['table']] ? $this->table2handlerKeys[$vArray['table']] : '_DEFAULT';
-                    // In case of separate handler keys for joined tables:
-                    if ($outputHandlerKey && $handlerKey != $outputHandlerKey) {
-                        throw new \RuntimeException('DBAL fatal error: Tables in this list "' . $tableList . '" didn\'t use the same DB handler!', 1310027833);
-                    }
-                    $outputHandlerKey = $handlerKey;
-                }
-                // Check initialized state; if handler is NOT initialized (connected) then we will connect it!
-                if (!isset($this->handlerInstance[$outputHandlerKey])) {
-                    $this->handler_init($outputHandlerKey);
-                }
-                // Return handler key:
-                $this->cache_handlerKeyFromTableList[$key] = $outputHandlerKey;
-            } else {
-                throw new \RuntimeException('DBAL fatal error: No handler found in handler_getFromTableList() for: "' . $tableList . '" (' . $tableArray . ')', 1310027933);
-            }
-        }
-        return $this->cache_handlerKeyFromTableList[$key];
-    }
-
-    /**
-     * Initialize handler (connecting to database)
-     *
-     * @param string $handlerKey Handler key
-     * @return bool If connection went well, return TRUE
-     * @throws \RuntimeException
-     * @see handler_getFromTableList()
-     */
-    public function handler_init($handlerKey)
-    {
-        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];
-        if (!$cfgArray['config']['database']) {
-            // Configuration is incomplete
-            return false;
-        }
-
-        $output = false;
-        switch ((string)$cfgArray['type']) {
-            case 'native':
-                $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'] : null
-                );
-                if ($connected) {
-                    // Set handler instance:
-                    $this->handlerInstance[$handlerKey] = ['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') {
-                        $this->link = $link;
-                        $this->isConnected = true;
-                        $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->checkConnectionCharset();
-                    }
-
-                    $output = true;
-                } else {
-                    GeneralUtility::sysLog('Could not connect to MySQL server ' . $cfgArray['config']['host'] . ' with user ' . $cfgArray['config']['username'] . '.', 'core', GeneralUtility::SYSLOG_SEVERITY_FATAL);
-                }
-                break;
-            case 'adodb':
-                $output = true;
-                require_once \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::extPath('adodb') . 'adodb/adodb.inc.php';
-                if (!defined('ADODB_FORCE_NULLS')) {
-                    define('ADODB_FORCE_NULLS', 1);
-                }
-                $GLOBALS['ADODB_FORCE_TYPE'] = ADODB_FORCE_VALUE;
-                $GLOBALS['ADODB_FETCH_MODE'] = ADODB_FETCH_BOTH;
-                $this->handlerInstance[$handlerKey] = ADONewConnection($cfgArray['config']['driver']);
-                // Set driver-specific options
-                if (isset($cfgArray['config']['driverOptions'])) {
-                    foreach ($cfgArray['config']['driverOptions'] as $optionName => $optionValue) {
-                        $optionSetterName = 'set' . ucfirst($optionName);
-                        if (method_exists($this->handlerInstance[$handlerKey], $optionSetterName)) {
-                            $this->handlerInstance[$handlerKey]->{$optionSetterName}($optionValue);
-                        } else {
-                            $this->handlerInstance[$handlerKey]->{$optionName} = $optionValue;
-                        }
-                    }
-                }
-                if ($GLOBALS['TYPO3_CONF_VARS']['SYS']['no_pconnect']) {
-                    $this->handlerInstance[$handlerKey]->Connect($cfgArray['config']['host'] . (isset($cfgArray['config']['port']) ? ':' . $cfgArray['config']['port'] : ''), $cfgArray['config']['username'], $cfgArray['config']['password'], $cfgArray['config']['database']);
-                } else {
-                    $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'] . ((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 {
-                    $this->handlerInstance[$handlerKey]->DataDictionary = NewDataDictionary($this->handlerInstance[$handlerKey]);
-                    $this->handlerInstance[$handlerKey]->last_insert_id = 0;
-                    if (isset($cfgArray['config']['sequenceStart'])) {
-                        $this->handlerInstance[$handlerKey]->sequenceStart = $cfgArray['config']['sequenceStart'];
-                    } else {
-                        $this->handlerInstance[$handlerKey]->sequenceStart = 1;
-                    }
-                }
-                break;
-            case 'userdefined':
-                // Initialize:
-                $this->handlerInstance[$handlerKey] = GeneralUtility::makeInstance($cfgArray['config']['class']);
-                $this->handlerInstance[$handlerKey]->init($cfgArray, $this);
-                if (is_object($this->handlerInstance[$handlerKey])) {
-                    $output = true;
-                }
-                break;
-            default:
-                throw new \RuntimeException('ERROR: Invalid handler type: "' . $cfgArray['type'] . '"', 1310027995);
-        }
-        return $output;
-    }
-
-    /**
-     * Checks if database is connected.
-     *
-     * @return bool
-     */
-    public function isConnected()
-    {
-        $result = false;
-        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;
-        }
-        return $result;
-    }
-
-    /**
-     * Checks whether the DBAL is currently inside an operation running on the "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';
-    }
-
-    /**
-     * Checks whether the ADOdb handler is running with a driver that contains the argument
-     *
-     * @param string $driver Driver name, matched with strstr().
-     * @return bool True if running with the given driver
-     */
-    public function runningADOdbDriver($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;
-    }
-
-    /************************************
-     *
-     * Table/Field mapping
-     *
-     **************************************/
-    /**
-     * Checks if mapping is needed for a table(list)
-     *
-     * @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 = [])
-    {
-        $key = $tableList . '|' . $fieldMappingOnly;
-        if (!isset($this->cache_mappingFromTableList[$key])) {
-            $this->cache_mappingFromTableList[$key] = false;
-            // Default:
-            $tables = $this->SQLparser->parseFromTables($tableList);
-            if (is_array($tables)) {
-                $parsedTableList = $tables;
-                foreach ($tables as $tableCfg) {
-                    if ($fieldMappingOnly) {
-                        if (is_array($this->mapping[$tableCfg['table']]['mapFieldNames'])) {
-                            $this->cache_mappingFromTableList[$key] = $tables;
-                        } elseif (is_array($tableCfg['JOIN'])) {
-                            foreach ($tableCfg['JOIN'] as $join) {
-                                if (is_array($this->mapping[$join['withTable']]['mapFieldNames'])) {
-                                    $this->cache_mappingFromTableList[$key] = $tables;
-                                    break;
-                                }
-                            }
-                        }
-                    } else {
-                        if (is_array($this->mapping[$tableCfg['table']])) {
-                            $this->cache_mappingFromTableList[$key] = $tables;
-                        } elseif (is_array($tableCfg['JOIN'])) {
-                            foreach ($tableCfg['JOIN'] as $join) {
-                                if (is_array($this->mapping[$join['withTable']])) {
-                                    $this->cache_mappingFromTableList[$key] = $tables;
-                                    break;
-                                }
-                            }
-                        }
-                    }
-                }
-            }
-        }
-        return $this->cache_mappingFromTableList[$key];
-    }
-
-    /**
-     * Takes an associated array with field => value pairs and remaps the field names if configured for this table in $this->mapping array.
-     * Be careful not to map a field name to another existing fields name (although you can use this to swap fieldnames of course...:-)
-     * 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 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):
-        foreach ($tables as $tableCfg) {
-            $tableKey = $this->getMappingKey($tableCfg['table']);
-            if (is_array($this->mapping[$tableKey]['mapFieldNames'])) {
-                // Get the map (reversed if needed):
-                if ($rev) {
-                    $theMap = array_flip($this->mapping[$tableKey]['mapFieldNames']);
-                } else {
-                    $theMap = $this->mapping[$tableKey]['mapFieldNames'];
-                }
-                // Traverse selected record, map fieldnames:
-                $output = [];
-                foreach ($input as $fN => $value) {
-                    // Set the field name, change it if found in mapping array:
-                    if ($theMap[$fN]) {
-                        $newKey = $theMap[$fN];
-                    } else {
-                        $newKey = $fN;
-                    }
-                    // Set value to fieldname:
-                    $output[$newKey] = $value;
-                }
-                // When done, override the $input array with the result:
-                $input = $output;
-            }
-        }
-        // Return input array (which might have been altered in the mean time)
-        return $input;
-    }
-
-    /**
-     * Remaps table/field names in a SELECT query's parts
-     *
-     * @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)
-    {
-        // Backup current mapping as it may be altered if aliases on mapped tables are found
-        $backupMapping = $this->mapping;
-        // Tables:
-        $tables = is_array($from_table) ? $from_table : $this->SQLparser->parseFromTables($from_table);
-        $defaultTable = $tables[0]['table'];
-        // Prepare mapping for aliased tables. This will copy the definition of the original table name.
-        // The alias is prefixed with a database-incompatible character to prevent naming clash with real table name
-        // Further access to $this->mapping should be made through $this->getMappingKey() method
-        foreach ($tables as $k => $v) {
-            if ($v['as'] && is_array($this->mapping[$v['table']]['mapFieldNames'])) {
-                $mappingKey = $this->getFreeMappingKey($v['as']);
-                $this->mapping[$mappingKey]['mapFieldNames'] =& $this->mapping[$v['table']]['mapFieldNames'];
-            }
-            if (is_array($v['JOIN'])) {
-                foreach ($v['JOIN'] as $joinCnt => $join) {
-                    if ($join['as'] && is_array($this->mapping[$join['withTable']]['mapFieldNames'])) {
-                        $mappingKey = $this->getFreeMappingKey($join['as']);
-                        $this->mapping[$mappingKey]['mapFieldNames'] =& $this->mapping[$join['withTable']]['mapFieldNames'];
-                    }
-                }
-            }
-        }
-        foreach ($tables as $k => $v) {
-            $tableKey = $this->getMappingKey($v['table']);
-            if ($this->mapping[$tableKey]['mapTableName']) {
-                $tables[$k]['table'] = $this->mapping[$tableKey]['mapTableName'];
-            }
-            // Mapping JOINS
-            if (is_array($v['JOIN'])) {
-                foreach ($v['JOIN'] as $joinCnt => $join) {
-                    // Mapping withTable of the JOIN
-                    $withTableKey = $this->getMappingKey($join['withTable']);
-                    if ($this->mapping[$withTableKey]['mapTableName']) {
-                        $tables[$k]['JOIN'][$joinCnt]['withTable'] = $this->mapping[$withTableKey]['mapTableName'];
-                    }
-                    $onPartsArray = [];
-                    // Mapping ON parts of the JOIN
-                    if (is_array($tables[$k]['JOIN'][$joinCnt]['ON'])) {
-                        foreach ($tables[$k]['JOIN'][$joinCnt]['ON'] as &$condition) {
-                            // Left side of the comparator
-                            $leftTableKey = $this->getMappingKey($condition['left']['table']);
-                            if (isset($this->mapping[$leftTableKey]['mapFieldNames'][$condition['left']['field']])) {
-                                $condition['left']['field'] = $this->mapping[$leftTableKey]['mapFieldNames'][$condition['left']['field']];
-                            }
-                            if (isset($this->mapping[$leftTableKey]['mapTableName'])) {
-                                $condition['left']['table'] = $this->mapping[$leftTableKey]['mapTableName'];
-                            }
-                            // Right side of the comparator
-                            $rightTableKey = $this->getMappingKey($condition['right']['table']);
-                            if (isset($this->mapping[$rightTableKey]['mapFieldNames'][$condition['right']['field']])) {
-                                $condition['right']['field'] = $this->mapping[$rightTableKey]['mapFieldNames'][$condition['right']['field']];
-                            }
-                            if (isset($this->mapping[$rightTableKey]['mapTableName'])) {
-                                $condition['right']['table'] = $this->mapping[$rightTableKey]['mapTableName'];
-                            }
-                        }
-                    }
-                }
-            }
-        }
-        $fromParts = $tables;
-        // Where clause:
-        $parameterReferences = [];
-        $whereParts = $this->SQLparser->parseWhereClause($where_clause, '', $parameterReferences);
-        $this->map_sqlParts($whereParts, $defaultTable);
-        // Select fields:
-        $selectParts = $this->SQLparser->parseFieldList($select_fields);
-        $this->map_sqlParts($selectParts, $defaultTable);
-        // Group By fields
-        $groupByParts = $this->SQLparser->parseFieldList($groupBy);
-        $this->map_sqlParts($groupByParts, $defaultTable);
-        // Order By fields
-        $orderByParts = $this->SQLparser->parseFieldList($orderBy);
-        $this->map_sqlParts($orderByParts, $defaultTable);
-        // Restore the original mapping
-        $this->mapping = $backupMapping;
-        return [$selectParts, $fromParts, $whereParts, $groupByParts, $orderByParts, $parameterReferences];
-    }
-
-    /**
-     * Returns the key to be used when retrieving information from $this->mapping. This ensures
-     * that mapping from aliased tables is properly retrieved.
-     *
-     * @param string $tableName
-     * @return string
-     */
-    protected function getMappingKey($tableName)
-    {
-        // Search deepest alias mapping
-        while (isset($this->mapping['*' . $tableName])) {
-            $tableName = '*' . $tableName;
-        }
-        return $tableName;
-    }
-
-    /**
-     * Returns a free key to be used to store mapping information in $this->mapping.
-     *
-     * @param string $tableName
-     * @return string
-     */
-    protected function getFreeMappingKey($tableName)
-    {
-        while (isset($this->mapping[$tableName])) {
-            $tableName = '*' . $tableName;
-        }
-        return $tableName;
-    }
-
-    /**
-     * Generic mapping of table/field names arrays (as parsed by \TYPO3\CMS\Dbal\Database\SqlParser)
-     *
-     * @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)
-    {
-        $defaultTableKey = $this->getMappingKey($defaultTable);
-        // Traverse sql Part array:
-        if (is_array($sqlPartArray)) {
-            foreach ($sqlPartArray as $k => $v) {
-                if (isset($sqlPartArray[$k]['type'])) {
-                    switch ($sqlPartArray[$k]['type']) {
-                        case 'flow-control':
-                            $temp = [$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;
-                                }
-                            }
-                            foreach ($sqlPartArray[$k]['when'] as $key => $when) {
-                                $this->map_sqlParts($sqlPartArray[$k]['when'][$key]['when_value'], $defaultTable);
-                            }
-                            break;
-                    }
-                }
-                // Look for sublevel (WHERE parts only)
-                if (is_array($sqlPartArray[$k]['sub'])) {
-                    $this->map_sqlParts($sqlPartArray[$k]['sub'], $defaultTable);
-                } 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;
-                    }
-                } else {
-                    // For the field, look for table mapping (generic):
-                    $t = $sqlPartArray[$k]['table'] ? $sqlPartArray[$k]['table'] : $defaultTable;
-                    $t = $this->getMappingKey($t);
-                    // Mapping field name, if set:
-                    if (is_array($this->mapping[$t]['mapFieldNames']) && isset($this->mapping[$t]['mapFieldNames'][$sqlPartArray[$k]['field']])) {
-                        $sqlPartArray[$k]['field'] = $this->mapping[$t]['mapFieldNames'][$sqlPartArray[$k]['field']];
-                    }
-                    // Mapping field name in SQL-functions like MIN(), MAX() or SUM()
-                    if ($this->mapping[$t]['mapFieldNames']) {
-                        $fieldArray = explode('.', $sqlPartArray[$k]['func_content']);
-                        $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 ($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]['func_content.'][0]['func_content'] = $table . '.' . $field;
-                            $sqlPartArray[$k]['func_content'] = $table . '.' . $field;
-                        }
-                        // Mapping flow-control statements
-                        if (isset($sqlPartArray[$k]['flow-control'])) {
-                            if (isset($sqlPartArray[$k]['flow-control']['type'])) {
-                                $temp = [$sqlPartArray[$k]['flow-control']];
-                                $this->map_sqlParts($temp, $t);
-                                // Call recursively!
-                                $sqlPartArray[$k]['flow-control'] = $temp[0];
-                            }
-                        }
-                    }
-                    // Do we have a function (e.g., CONCAT)
-                    if (isset($v['value']['operator'])) {
-                        foreach ($sqlPartArray[$k]['value']['args'] as $argK => $fieldDef) {
-                            $tableKey = $this->getMappingKey($fieldDef['table']);
-                            if (isset($this->mapping[$tableKey]['mapTableName'])) {
-                                $sqlPartArray[$k]['value']['args'][$argK]['table'] = $this->mapping[$tableKey]['mapTableName'];
-                            }
-                            if (is_array($this->mapping[$tableKey]['mapFieldNames']) && isset($this->mapping[$tableKey]['mapFieldNames'][$fieldDef['field']])) {
-                                $sqlPartArray[$k]['value']['args'][$argK]['field'] = $this->mapping[$tableKey]['mapFieldNames'][$fieldDef['field']];
-                            }
-                        }
-                    }
-                    // Do we have a subquery (WHERE parts only)?
-                    if (isset($sqlPartArray[$k]['subquery'])) {
-                        $this->map_subquery($sqlPartArray[$k]['subquery']);
-                    }
-                    // do we have a field name in the value?
-                    // this is a very simplistic check, beware
-                    if (!is_numeric($sqlPartArray[$k]['value'][0]) && !isset($sqlPartArray[$k]['value'][1])) {
-                        $fieldArray = explode('.', $sqlPartArray[$k]['value'][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 ($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]['value'][0] = $table . '.' . $field;
-                        }
-                    }
-                    // Map table?
-                    $tableKey = $this->getMappingKey($sqlPartArray[$k]['table']);
-                    if ($sqlPartArray[$k]['table'] && $this->mapping[$tableKey]['mapTableName']) {
-                        $sqlPartArray[$k]['table'] = $this->mapping[$tableKey]['mapTableName'];
-                    }
-                }
-            }
-        }
-    }
-
-    /**
-     * Maps table and field names in a subquery.
-     *
-     * @param array $parsedQuery
-     * @return void
-     */
-    protected function map_subquery(&$parsedQuery)
-    {
-        // Backup current mapping as it may be altered
-        $backupMapping = $this->mapping;
-        foreach ($parsedQuery['FROM'] as $k => $v) {
-            $mappingKey = $v['table'];
-            if ($v['as'] && is_array($this->mapping[$v['table']]['mapFieldNames'])) {
-                $mappingKey = $this->getFreeMappingKey($v['as']);
-            } else {
-                // Should ensure that no alias is defined in the external query
-                // which would correspond to a real table name in the subquery
-                if ($this->getMappingKey($v['table']) !== $v['table']) {
-                    $mappingKey = $this->getFreeMappingKey($v['table']);
-                    // This is the only case when 'mapTableName' should be copied
-                    $this->mapping[$mappingKey]['mapTableName'] =& $this->mapping[$v['table']]['mapTableName'];
-                }
-            }
-            if ($mappingKey !== $v['table']) {
-                $this->mapping[$mappingKey]['mapFieldNames'] =& $this->mapping[$v['table']]['mapFieldNames'];
-            }
-        }
-        // Perform subquery's remapping
-        $defaultTable = $parsedQuery['FROM'][0]['table'];
-        $this->map_sqlParts($parsedQuery['SELECT'], $defaultTable);
-        $this->map_sqlParts($parsedQuery['FROM'], $defaultTable);
-        $this->map_sqlParts($parsedQuery['WHERE'], $defaultTable);
-        // Restore the mapping
-        $this->mapping = $backupMapping;
-    }
-
-    /**
-     * 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 $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) {
-            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']];
-                    if ($newFieldName) {
-                        if ($parsedQuery['FIELD'] == $parsedQuery['newField']) {
-                            $parsedQuery['FIELD'] = ($parsedQuery['newField'] = $newFieldName);
-                        } else {
-                            $parsedQuery['FIELD'] = $newFieldName;
-                        }
-                    }
-                    // Changing key field names:
-                    if (is_array($parsedQuery['fields'])) {
-                        $this->map_fieldNamesInArray($table, $parsedQuery['fields']);
-                    }
-                    break;
-                case 'CREATETABLE':
-                    // Remapping fields:
-                    if (is_array($parsedQuery['FIELDS'])) {
-                        $newFieldsArray = [];
-                        foreach ($parsedQuery['FIELDS'] as $fN => $fInfo) {
-                            if ($this->mapping[$table]['mapFieldNames'][$fN]) {
-                                $fN = $this->mapping[$table]['mapFieldNames'][$fN];
-                            }
-                            $newFieldsArray[$fN] = $fInfo;
-                        }
-                        $parsedQuery['FIELDS'] = $newFieldsArray;
-                    }
-                    // Remapping keys:
-                    if (is_array($parsedQuery['KEYS'])) {
-                        foreach ($parsedQuery['KEYS'] as $kN => $kInfo) {
-                            $this->map_fieldNamesInArray($table, $parsedQuery['KEYS'][$kN]);
-                        }
-                    }
-                    break;
-            }
-        }
-    }
-
-    /**
-     * Re-mapping field names in array
-     *
-     * @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'])) {
-            foreach ($fieldArray as $k => $v) {
-                if ($this->mapping[$table]['mapFieldNames'][$v]) {
-                    $fieldArray[$k] = $this->mapping[$table]['mapFieldNames'][$v];
-                }
-            }
-        }
-    }
-
-    /**
-     * 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 = [];
-        $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, [$table => $mappingConfiguration]);
-        }
-    }
-
-    /**************************************
-     *
-     * Debugging
-     *
-     **************************************/
-    /**
-     * Debug handler for query execution
-     *
-     * @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 = \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 = [];
-            $errorFlag = 0;
-            $joinTable = '';
-            if ($this->sql_error()) {
-                $data['sqlError'] = $this->sql_error();
-                $errorFlag |= 1;
-            }
-            // if lastQuery is empty (for whatever reason) at least log inData.args
-            if (empty($this->lastQuery)) {
-                $query = implode(' ', $inData['args']);
-            } else {
-                $query = $this->lastQuery;
-            }
-            if ($this->conf['debugOptions']['numberRows']) {
-                switch ($function) {
-                    case 'exec_INSERTquery':
-
-                    case 'exec_UPDATEquery':
-
-                    case 'exec_DELETEquery':
-                        $data['numberRows'] = $this->sql_affected_rows();
-                        break;
-                    case 'exec_SELECTquery':
-                        $data['numberRows'] = $inData['numberRows'];
-                        break;
-                }
-            }
-            if ($this->conf['debugOptions']['backtrace']) {
-                $backtrace = debug_backtrace(0);
-                $data['backtrace'] = array_slice($backtrace, 1, $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'] && ($inData['handlerType'] === 'adodb' || $inData['handlerType'] === 'native')) {
-                        $data['EXPLAIN'] = $this->debug_explain($this->lastQuery);
-                    }
-                    // Check parsing of Query:
-                    if ($this->conf['debugOptions']['parseQuery']) {
-                        $parseResults = [];
-                        $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;
-                        }
-                    }
-                    // 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);
-                    }
-                    break;
-            }
-        }
-    }
-
-    /**
-     * Logs the where clause for debugging purposes.
-     *
-     * @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
-     * @return void
-     */
-    public function debug_WHERE($table, $where, $script = '')
-    {
-        $insertArray = [
-            'tstamp' => $GLOBALS['EXEC_TIME'],
-            'beuser_id' => (int)$GLOBALS['BE_USER']->user['uid'],
-            'script' => $script,
-            'tablename' => $table,
-            'whereclause' => $where
-        ];
-        $this->exec_INSERTquery('tx_dbal_debuglog_where', $insertArray);
-    }
-
-    /**
-     * Inserts row in the log table
-     *
-     * @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 (!empty($query[1])) {
-                $queryToLog .= count($query[1]) . ' BLOB FIELDS: ' . implode(', ', array_keys($query[1]));
-            }
-            if (!empty($query[2])) {
-                $queryToLog .= count($query[2]) . ' CLOB FIELDS: ' . implode(', ', array_keys($query[2]));
-            }
-        } else {
-            $queryToLog = $query;
-        }
-        $insertArray = [
-            'tstamp' => $GLOBALS['EXEC_TIME'],
-            'beuser_id' => (int)$GLOBALS['BE_USER']->user['uid'],
-            'script' => $script,
-            'exec_time' => $ms,
-            'table_join' => $join,
-            'serdata' => serialize($data),
-            'query' => $queryToLog,
-            'errorFlag' => $errorFlag
-        ];
-        $this->exec_INSERTquery('tx_dbal_debuglog', $insertArray);
-    }
-
-    /**
-     * Perform EXPLAIN query on DEFAULT handler!
-     *
-     * @param string $query SELECT Query
-     * @return array The Explain result rows in an array
-     */
-    public function debug_explain($query)
-    {
-        $output = [];
-        $hType = (string)$this->handlerCfg[$this->lastHandlerKey]['type'];
-        switch ($hType) {
-            case 'native':
-                $res = $this->sql_query('EXPLAIN ' . $query);
-                while ($row = $this->sql_fetch_assoc($res)) {
-                    $output[] = $row;
-                }
-                break;
-            case 'adodb':
-                switch ($this->handlerCfg['_DEFAULT']['config']['driver']) {
-                    case 'oci8':
-                        $this->sql_query('EXPLAIN PLAN ' . $query);
-                        $output[] = 'EXPLAIN PLAN data logged to default PLAN_TABLE';
-                        break;
-                    default:
-                        $res = $this->sql_query('EXPLAIN ' . $query);
-                        while ($row = $this->sql_fetch_assoc($res)) {
-                            $output[] = $row;
-                        }
-                }
-                break;
-        }
-        return $output;
-    }
-}
diff --git a/typo3/sysext/dbal/Classes/Database/Specifics/AbstractSpecifics.php b/typo3/sysext/dbal/Classes/Database/Specifics/AbstractSpecifics.php
deleted file mode 100644 (file)
index 203b8e6..0000000
+++ /dev/null
@@ -1,313 +0,0 @@
-<?php
-namespace TYPO3\CMS\Dbal\Database\Specifics;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * 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.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-/**
- * This class handles the specifics of the active DBMS. Inheriting classes
- * are intended to define their own specifics.
- */
-abstract class AbstractSpecifics
-{
-    /**
-     * Constants used as identifiers in $specificProperties.
-     */
-    const TABLE_MAXLENGTH = 'table_maxlength';
-    const FIELD_MAXLENGTH = 'field_maxlength';
-    const LIST_MAXEXPRESSIONS = 'list_maxexpressions';
-    const PARTIAL_STRING_INDEX = 'partial_string_index';
-    const CAST_FIND_IN_SET = 'cast_find_in_set';
-
-    /**
-     * Contains the specifics of a DBMS.
-     * This is intended to be overridden by inheriting classes.
-     *
-     * @var array
-     */
-    protected $specificProperties = [];
-
-    /**
-     * Contains the DBMS specific mapping information for native MySQL to ADOdb meta field types
-     *
-     * @var array
-     */
-    protected $nativeToMetaFieldTypeMap = [
-        'STRING' => 'C',
-        'CHAR' => 'C',
-        'VARCHAR' => 'C',
-        'TINYBLOB' => 'C',
-        'TINYTEXT' => 'C',
-        'ENUM' => 'C',
-        'SET' => 'C',
-        'TEXT' => 'XL',
-        'LONGTEXT' => 'XL',
-        'MEDIUMTEXT' => 'XL',
-        'IMAGE' => 'B',
-        'LONGBLOB' => 'B',
-        'BLOB' => 'B',
-        'MEDIUMBLOB' => 'B',
-        'YEAR' => 'D',
-        'DATE' => 'D',
-        'TIME' => 'T',
-        'DATETIME' => 'T',
-        'TIMESTAMP' => 'T',
-        'FLOAT' => 'F',
-        'DOUBLE' => 'F',
-        'INT' => 'I8',
-        'INTEGER' => 'I8',
-        'TINYINT' => 'I8',
-        'SMALLINT' => 'I8',
-        'MEDIUMINT' => 'I8',
-        'BIGINT' => 'I8',
-    ];
-
-    /**
-     * Contains the DBMS specific mapping overrides for native MySQL to ADOdb meta field types
-     */
-    protected $nativeToMetaFieldTypeOverrides = [];
-
-    /**
-     * Contains the default mapping information for ADOdb meta to MySQL native field types
-     *
-     * @var array
-     */
-    protected $metaToNativeFieldTypeMap = [
-        'C' => 'VARCHAR',
-        'C2' => 'VARCHAR',
-        'X' => 'LONGTEXT',
-        'XL' => 'LONGTEXT',
-        'X2' => 'LONGTEXT',
-        'B' => 'LONGBLOB',
-        'D' => 'DATE',
-        'T' => 'DATETIME',
-        'L' => 'TINYINT',
-        'I' => 'BIGINT',
-        'I1' => 'BIGINT',
-        'I2' => 'BIGINT',
-        'I4' => 'BIGINT',
-        'I8' => 'BIGINT',
-        'F' => 'DOUBLE',
-        'N' => 'NUMERIC'
-    ];
-
-    /**
-     * Contains the DBMS specific mapping information for ADOdb meta field types to MySQL native field types
-     *
-     * @var array
-     */
-    protected $metaToNativeFieldTypeOverrides = [];
-
-    /**
-     * Constructor
-     */
-    public function __construct()
-    {
-        $this->nativeToMetaFieldTypeMap = array_merge($this->nativeToMetaFieldTypeMap, $this->nativeToMetaFieldTypeOverrides);
-        $this->metaToNativeFieldTypeMap = array_merge($this->metaToNativeFieldTypeMap, $this->metaToNativeFieldTypeOverrides);
-    }
-
-    /**
-     * Checks if a specific is defined for the used DBMS.
-     *
-     * @param string $specific
-     * @return bool
-     */
-    public function specificExists($specific)
-    {
-        return isset($this->specificProperties[$specific]);
-    }
-
-    /**
-     * Gets the specific value.
-     *
-     * @param string $specific
-     * @return mixed
-     */
-    public function getSpecific($specific)
-    {
-        return $this->specificProperties[$specific];
-    }
-
-    /**
-     * Splits $expressionList into multiple chunks.
-     *
-     * @param array $expressionList
-     * @param bool $preserveArrayKeys If TRUE, array keys are preserved in array_chunk()
-     * @return array
-     */
-    public function splitMaxExpressions($expressionList, $preserveArrayKeys = false)
-    {
-        if (!$this->specificExists(self::LIST_MAXEXPRESSIONS)) {
-            return [$expressionList];
-        }
-
-        return array_chunk($expressionList, $this->getSpecific(self::LIST_MAXEXPRESSIONS), $preserveArrayKeys);
-    }
-
-    /**
-     * Truncates the name of the identifier.
-     * Based on TYPO3.FLOWs' FlowAnnotationDriver::truncateIdentifier()
-     *
-     * @param string $identifier
-     * @param string $specific
-     * @return string
-     */
-    public function truncateIdentifier($identifier, $specific)
-    {
-        if (!$this->specificExists($specific)) {
-            return $identifier;
-        }
-
-        $maxLength = $this->getSpecific($specific);
-        if (strlen($identifier) > $maxLength) {
-            $truncateChars = 10;
-            $identifier = substr($identifier, 0, $maxLength - $truncateChars) . '_' . substr(sha1($identifier), 0, $truncateChars - 1);
-        }
-
-        return $identifier;
-    }
-
-    /**
-     * Adjust query parts for DBMS
-     *
-     * @param string $select_fields
-     * @param string $from_table
-     * @param string $where_clause
-     * @param string $groupBy
-     * @param string $orderBy
-     * @param string $limit
-     * @return void
-     */
-    public function transformQueryParts(&$select_fields, &$from_table, &$where_clause, &$groupBy = '', &$orderBy = '', &$limit = '')
-    {
-    }
-
-    /**
-     * Transforms a database specific representation of field information and translates it
-     * as close as possible to the MySQL standard.
-     *
-     * @param array $fieldRow
-     * @param string $metaType
-     * @return array
-     */
-    public function transformFieldRowToMySQL($fieldRow, $metaType)
-    {
-        $mysqlType = $this->getNativeFieldType($metaType);
-        $mysqlType .= $this->getNativeFieldLength($mysqlType, $fieldRow['max_length']);
-
-        $fieldRow['Field'] = $fieldRow['name'];
-        $fieldRow['Type'] = strtolower($mysqlType);
-        $fieldRow['Null'] = $this->getNativeNotNull($fieldRow['not_null']);
-        $fieldRow['Key'] = $this->getNativeKeyForField($fieldRow);
-        $fieldRow['Default'] = $this->getNativeDefaultValue($fieldRow);
-        $fieldRow['Extra'] = $this->getNativeExtraFieldAttributes($fieldRow);
-
-        return $fieldRow;
-    }
-
-    /**
-     * Return actual MySQL type for meta field type
-     *
-     * @param string $metaType 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
-     */
-    public function getNativeFieldType($metaType)
-    {
-        $metaType = strtoupper($metaType);
-        return empty($this->metaToNativeFieldTypeMap[$metaType]) ? $metaType : $this->metaToNativeFieldTypeMap[$metaType];
-    }
-
-    /**
-     * Return MetaType for native MySQL field type
-     *
-     * @param string $nativeType 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)
-     */
-    public function getMetaFieldType($nativeType)
-    {
-        $nativeType = strtoupper($nativeType);
-        return empty($this->nativeToMetaFieldTypeMap[$nativeType]) ? 'N' : $this->nativeToMetaFieldTypeMap[$nativeType];
-    }
-
-    /**
-     * Determine the native field length information for a table field.
-     *
-     * @param string  $mysqlType
-     * @param int $maxLength
-     * @return string
-     */
-    public function getNativeFieldLength($mysqlType, $maxLength)
-    {
-        if ($maxLength === -1) {
-            return '';
-        }
-        switch ($mysqlType) {
-            case 'INT':
-                return '(11)';
-            default:
-                return '(' . $maxLength . ')';
-        }
-    }
-
-    /**
-     * Return the MySQL native representation of the NOT NULL setting
-     *
-     * @param mixed $notNull
-     * @return string
-     */
-    protected function getNativeNotNull($notNull)
-    {
-        return (bool)$notNull ? 'NO' : 'YES';
-    }
-
-    /**
-     * Return the default value of a field formatted to match the native MySQL SQL dialect
-     *
-     * @param array $fieldDefinition
-     * @return mixed
-     */
-    protected function getNativeDefaultValue($fieldDefinition)
-    {
-        return $fieldDefinition['default_value'];
-    }
-
-    /**
-     * Return the MySQL native key type indicator - https://dev.mysql.com/doc/refman/5.5/en/show-columns.html
-     * PRI - the column is a PRIMARY KEY or is one of the columns in a multiple-column PRIMARY KEY
-     * UNI - the column is the first column of a UNIQUE index
-     * MUL - the column is the first column of a nonunique index
-     * If more than one of the values applies return the one with the highest priority, in the order PRI, UNI, MUL
-     * If none applies return empty value.
-     *
-     * @param array $fieldRow
-     * @return string
-     */
-    protected function getNativeKeyForField($fieldRow)
-    {
-        return '';
-    }
-
-    /**
-     * Return the MySQL native extra field information - https://dev.mysql.com/doc/refman/5.5/en/show-columns.html
-     * auto_increment for columns that have the AUTO_INCREMENT attribute
-     * on update CURRENT_TIMESTAMP for TIMESTAMP columns that have the ON UPDATE CURRENT_TIMESTAMP attribute.
-     *
-     * @param array $fieldRow
-     * @return string
-     */
-    protected function getNativeExtraFieldAttributes($fieldRow)
-    {
-        return '';
-    }
-}
diff --git a/typo3/sysext/dbal/Classes/Database/Specifics/NullSpecifics.php b/typo3/sysext/dbal/Classes/Database/Specifics/NullSpecifics.php
deleted file mode 100644 (file)
index 55a28bd..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-<?php
-namespace TYPO3\CMS\Dbal\Database\Specifics;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * 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.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-/**
- * This class contains a null driver for specifics used by any
- * DBMS that does not have its own requirements.
- * Any logic is in AbstractSpecifics.
- */
-class NullSpecifics extends AbstractSpecifics
-{
-}
diff --git a/typo3/sysext/dbal/Classes/Database/Specifics/Oci8Specifics.php b/typo3/sysext/dbal/Classes/Database/Specifics/Oci8Specifics.php
deleted file mode 100644 (file)
index eb5ef90..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-<?php
-namespace TYPO3\CMS\Dbal\Database\Specifics;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * 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.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-/**
- * This class contains the specifics for Oracle DBMS.
- * Any logic is in AbstractSpecifics.
- */
-class Oci8Specifics extends AbstractSpecifics
-{
-    /**
-     * Contains the specifics that need to be taken care of for Oracle DBMS.
-     *
-     * @var array
-     */
-    protected $specificProperties = [
-        self::TABLE_MAXLENGTH => 30,
-        self::FIELD_MAXLENGTH => 30,
-        self::LIST_MAXEXPRESSIONS => 1000
-    ];
-}
diff --git a/typo3/sysext/dbal/Classes/Database/Specifics/PostgresSpecifics.php b/typo3/sysext/dbal/Classes/Database/Specifics/PostgresSpecifics.php
deleted file mode 100644 (file)
index f9ad3cc..0000000
+++ /dev/null
@@ -1,190 +0,0 @@
-<?php
-namespace TYPO3\CMS\Dbal\Database\Specifics;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * 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.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-use TYPO3\CMS\Core\Utility\GeneralUtility;
-use TYPO3\CMS\Core\Utility\StringUtility;
-
-/**
- * This class contains the specifics for PostgreSQL DBMS.
- * Any logic is in AbstractSpecifics.
- */
-class PostgresSpecifics extends AbstractSpecifics
-{
-    /**
-     * Contains the specifics that need to be taken care of for PostgreSQL DBMS.
-     *
-     * @var array
-     */
-    protected $specificProperties = [
-        self::CAST_FIND_IN_SET => true
-    ];
-
-    /**
-     * Contains the DBMS specific mapping overrides for native MySQL to ADOdb meta field types
-     */
-    protected $nativeToMetaFieldTypeOverrides = [
-        'TINYBLOB' => 'B',
-        'INT' => 'I4',
-        'INTEGER' => 'I4',
-        'TINYINT' => 'I2',
-        'SMALLINT' => 'I2',
-        'MEDIUMINT' => 'I4'
-    ];
-
-    /**
-     * Contains the DBMS specific mapping information for ADOdb meta field types to MySQL native field types
-     *
-     * @var array
-     */
-    protected $metaToNativeFieldTypeOverrides = [
-        'R' => 'INT',
-        'I' => 'INT',
-        'I1' => 'SMALLINT',
-        'I2' => 'SMALLINT',
-        'I4' => 'INT',
-    ];
-
-    /**
-     * Determine the native field length information for a table field.
-     *
-     * @param string $mysqlType
-     * @param int $maxLength
-     * @return string
-     */
-    public function getNativeFieldLength($mysqlType, $maxLength)
-    {
-        if ($maxLength === -1) {
-            return '';
-        }
-        switch ($mysqlType) {
-            case 'DOUBLE':
-                return '';
-            case 'TINYINT':
-                return '(4)';
-            case 'SMALLINT':
-                return '(6)';
-            case 'MEDIUMINT':
-                return '(9)';
-            case 'INT':
-                return '(11)';
-            case 'BIGINT':
-                return '(20)';
-            default:
-                return '(' . $maxLength . ')';
-        }
-    }
-
-    /**
-     * Return the default value of a field formatted to match the native MySQL SQL dialect
-     *
-     * @param array $fieldDefinition
-     * @return mixed
-     */
-    protected function getNativeDefaultValue($fieldDefinition)
-    {
-        if (!$fieldDefinition['has_default']) {
-            $returnValue = null;
-        } elseif ($fieldDefinition['type'] === 'SERIAL' && substr($fieldDefinition['default_value'], 0, 7) === 'nextval') {
-            $returnValue = null;
-        } elseif ($fieldDefinition['type'] === 'varchar') {
-            // Strip character class and unquote string
-            if (StringUtility::beginsWith($fieldDefinition['default_value'], 'NULL::')) {
-                $returnValue = null;
-            } else {
-                $returnValue = str_replace("\\'", "'", preg_replace('/\'(.*)\'(::(?:character\svarying|varchar|character|char|text)(?:\(\d+\))?)?\z/', '\\1', $fieldDefinition['default_value']));
-            }
-        } elseif (substr($fieldDefinition['type'], 0, 3) === 'int') {
-            $returnValue = (int)preg_replace('/^\(?(\-?\d+)\)?$/', '\\1', $fieldDefinition['default_value']);
-        } else {
-            $returnValue = $fieldDefinition['default_value'];
-        }
-        return $returnValue;
-    }
-
-    /**
-     * Return the MySQL native key type indicator - https://dev.mysql.com/doc/refman/5.5/en/show-columns.html
-     * PRI - the column is a PRIMARY KEY or is one of the columns in a multiple-column PRIMARY KEY
-     * UNI - the column is the first column of a UNIQUE index
-     * MUL - the column is the first column of a nonunique index
-     * If more than one of the values applies return the one with the highest priority, in the order PRI, UNI, MUL
-     * If none applies return empty value.
-     *
-     * @param array $fieldDefinition
-     * @return string
-     */
-    protected function getNativeKeyForField($fieldDefinition)
-    {
-        if (isset($fieldDefinition['primary_key']) && (bool)$fieldDefinition['primary_key']) {
-            $returnValue = 'PRI';
-        } elseif (isset($fieldDefinition['unique']) && (bool)$fieldDefinition['unique']) {
-            $returnValue = 'UNI';
-        } else {
-            $returnValue = '';
-        }
-        return $returnValue;
-    }
-
-    /**
-     * Return the MySQL native extra field information - https://dev.mysql.com/doc/refman/5.5/en/show-columns.html
-     * auto_increment for columns that have the AUTO_INCREMENT attribute
-     * on update CURRENT_TIMESTAMP for TIMESTAMP columns that have the ON UPDATE CURRENT_TIMESTAMP attribute.
-     *
-     * @param array $fieldDefinition
-     * @return string
-     */
-    protected function getNativeExtraFieldAttributes($fieldDefinition)
-    {
-        if ($fieldDefinition['type'] === 'SERIAL' || substr($fieldDefinition['default_value'], 0, 7) === 'nextval') {
-            return 'auto_increment';
-        }
-        return '';
-    }
-
-    /**
-     * Adjust query parts for various DBMS
-     *
-     * @param string $select_fields
-     * @param string $from_table
-     * @param string $where_clause
-     * @param string $groupBy
-     * @param string $orderBy
-     * @param string $limit
-     * @return void
-     */
-    public function transformQueryParts(&$select_fields, &$from_table, &$where_clause, &$groupBy = '', &$orderBy = '', &$limit = '')
-    {
-        // Strip orderBy part if select statement is a count
-        if (preg_match_all('/count\(([^)]*)\)/i', $select_fields, $matches)) {
-            $orderByFields = GeneralUtility::trimExplode(',', $orderBy);
-            $groupByFields = GeneralUtility::trimExplode(',', $groupBy);
-            foreach ($matches[1] as $matchedField) {
-                $field = $matchedField;
-                // Lookup if the field in COUNT() statement is used in GROUP BY statement
-                $index = array_search($field, $groupByFields, true);
-                if ($index !== false) {
-                    // field is used in GROUP BY, continue with next field
-                    continue;
-                }
-                // If that field isn't used in GROUP BY statement, drop the ordering for compatibility reason
-                $index = array_search($field, $orderByFields, true);
-                if ($index !== false) {
-                    unset($orderByFields[$index]);
-                }
-            }
-            $orderBy = implode(', ', $orderByFields);
-        }
-    }
-}
diff --git a/typo3/sysext/dbal/Classes/Database/SqlCompilers/AbstractCompiler.php b/typo3/sysext/dbal/Classes/Database/SqlCompilers/AbstractCompiler.php
deleted file mode 100644 (file)
index 4fd14aa..0000000
+++ /dev/null
@@ -1,324 +0,0 @@
-<?php
-namespace TYPO3\CMS\Dbal\Database\SqlCompilers;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * 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.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-use TYPO3\CMS\Dbal\Database\DatabaseConnection;
-
-/**
- * Abstract base class for SQL compilers
- */
-abstract class AbstractCompiler
-{
-    /**
-     * @var \TYPO3\CMS\Dbal\Database\DatabaseConnection
-     */
-    protected $databaseConnection;
-
-    /**
-     * @param \TYPO3\CMS\Dbal\Database\DatabaseConnection $databaseConnection
-     */
-    public function __construct(DatabaseConnection $databaseConnection)
-    {
-        $this->databaseConnection = $databaseConnection;
-    }
-
-    /**
-     * Compiles an SQL query from components
-     *
-     * @param array $components Array of SQL query components
-     * @return string SQL query
-     * @see parseSQL()
-     */
-    public function compileSQL($components)
-    {
-        $query = '';
-        switch ($components['type']) {
-            case 'SELECT':
-                $query = $this->compileSELECT($components);
-                break;
-            case 'UPDATE':
-                $query = $this->compileUPDATE($components);
-                break;
-            case 'INSERT':
-                $query = $this->compileINSERT($components);
-                break;
-            case 'DELETE':
-                $query = $this->compileDELETE($components);
-                break;
-            case 'EXPLAIN':
-                $query = 'EXPLAIN ' . $this->compileSELECT($components);
-                break;
-            case 'DROPTABLE':
-                $query = 'DROP TABLE' . ($components['ifExists'] ? ' IF EXISTS' : '') . ' ' . $components['TABLE'];
-                break;
-            case 'CREATETABLE':
-                $query = $this->compileCREATETABLE($components);
-                break;
-            case 'ALTERTABLE':
-                $query = $this->compileALTERTABLE($components);
-                break;
-            case 'TRUNCATETABLE':
-                $query = $this->compileTRUNCATETABLE($components);
-                break;
-        }
-        return $query;
-    }
-
-    /**
-     * Compiles a SELECT statement from components array
-     *
-     * @param array $components Array of SQL query components
-     * @return string SQL SELECT query
-     * @see parseSELECT()
-     */
-    protected function compileSELECT($components)
-    {
-        // Initialize:
-        $where = $this->compileWhereClause($components['WHERE']);
-        $groupBy = $this->compileFieldList($components['GROUPBY']);
-        $orderBy = $this->compileFieldList($components['ORDERBY']);
-        $limit = $components['LIMIT'];
-        // Make query:
-        $query = 'SELECT ' . ($components['STRAIGHT_JOIN'] ?: '') . ' ' .
-            $this->compileFieldList($components['SELECT']) .
-            ' FROM ' . $this->compileFromTables($components['FROM']) . ($where !== '' ?
-                ' WHERE ' . $where : '') . ($groupBy !== '' ?
-                ' GROUP BY ' . $groupBy : '') . ($orderBy !== '' ?
-                ' ORDER BY ' . $orderBy : '') . ((string)$limit !== '' ?
-                ' LIMIT ' . $limit : '');
-        return $query;
-    }
-
-    /**
-     * Compiles an UPDATE statement from components array
-     *
-     * @param array $components Array of SQL query components
-     * @return string SQL UPDATE query
-     * @see parseUPDATE()
-     */
-    protected function compileUPDATE($components)
-    {
-        // Where clause:
-        $where = $this->compileWhereClause($components['WHERE']);
-        // Fields
-        $fields = [];
-        foreach ($components['FIELDS'] as $fN => $fV) {
-            $fields[] = $fN . '=' . $fV[1] . $this->compileAddslashes($fV[0]) . $fV[1];
-        }
-        // Make query:
-        $query = 'UPDATE ' . $components['TABLE'] . ' SET ' . implode(',', $fields) .
-            ($where !== '' ? ' WHERE ' . $where : '');
-
-        return $query;
-    }
-
-    /**
-     * Compiles an INSERT statement from components array
-     *
-     * @param array $components Array of SQL query components
-     * @return string SQL INSERT query
-     * @see parseINSERT()
-     */
-    abstract protected function compileINSERT($components);
-
-    /**
-     * Compiles an DELETE statement from components array
-     *
-     * @param array $components Array of SQL query components
-     * @return string SQL DELETE query
-     * @see parseDELETE()
-     */
-    protected function compileDELETE($components)
-    {
-        // Where clause:
-        $where = $this->compileWhereClause($components['WHERE']);
-        // Make query:
-        $query = 'DELETE FROM ' . $components['TABLE'] . ($where !== '' ? ' WHERE ' . $where : '');
-
-        return $query;
-    }
-
-    /**
-     * Compiles a CREATE TABLE statement from components array
-     *
-     * @param array $components Array of SQL query components
-     * @return array array with SQL CREATE TABLE/INDEX command(s)
-     * @see parseCREATETABLE()
-     */
-    abstract protected function compileCREATETABLE($components);
-
-    /**
-     * Compiles an ALTER TABLE statement from components array
-     *
-     * @param array Array of SQL query components
-     * @return string SQL ALTER TABLE query
-     * @see parseALTERTABLE()
-     */
-    abstract protected function compileALTERTABLE($components);
-
-    /**
-     * Compiles a TRUNCATE TABLE statement from components array
-     *
-     * @param array $components Array of SQL query components
-     * @return string SQL TRUNCATE TABLE query
-     * @see parseTRUNCATETABLE()
-     */
-    protected function compileTRUNCATETABLE(array $components)
-    {
-        // Make query:
-        $query = 'TRUNCATE TABLE ' . $components['TABLE'];
-        // Return query
-        return $query;
-    }
-
-    /**
-     * Compiles a "SELECT [output] FROM..:" field list based on input array (made with ->parseFieldList())
-     * Can also compile field lists for ORDER BY and GROUP BY.
-     *
-     * @param array $selectFields Array of select fields, (made with ->parseFieldList())
-     * @param bool $compileComments Whether comments should be compiled
-     * @param bool $functionMapping Whether function mapping should take place
-     * @return string Select field string
-     * @see parseFieldList()
-     */
-    abstract public function compileFieldList($selectFields, $compileComments = true, $functionMapping = true);
-
-    /**
-     * Implodes an array of WHERE clause configuration into a WHERE clause.
-     *
-     * DBAL-specific: The only(!) handled "calc" operators supported by parseWhereClause() are:
-     * - the bitwise logical and (&)
-     * - the addition (+)
-     * - the substraction (-)
-     * - the multiplication (*)
-     * - the division (/)
-     * - the modulo (%)
-     *
-     * @param array $clauseArray
-     * @param bool $functionMapping
-     * @return string WHERE clause as string.
-     * @see \TYPO3\CMS\Core\Database\SqlParser::parseWhereClause()
-     */
-    abstract public function compileWhereClause($clauseArray, $functionMapping = true);
-
-    /**
-     * Add slashes function used for compiling queries
-     * This method overrides the method from \TYPO3\CMS\Dbal\Database\NativeSqlParser because
-     * the input string is already properly escaped.
-     *
-     * @param string $str Input string
-     * @return string Output string
-     */
-    abstract protected function compileAddslashes($str);
-
-    /**
-     * Compile a "JOIN table ON [output] = ..." identifier
-     *
-     * @param array $identifierParts Array of identifier parts
-     * @return string
-     * @see parseCastStatement()
-     * @see parseFromTables()
-     */
-    protected function compileJoinIdentifier($identifierParts)
-    {
-        if ($identifierParts['type'] === 'cast') {
-            return sprintf('CAST(%s AS %s)',
-                $identifierParts['table'] ? $identifierParts['table'] . '.' . $identifierParts['field'] : $identifierParts['field'],
-                $identifierParts['datatype'][0]
-            );
-        } else {
-            return $identifierParts['table'] ? $identifierParts['table'] . '.' . $identifierParts['field'] : $identifierParts['field'];
-        }
-    }
-
-    /**
-     * Compiles a "FROM [output] WHERE..:" table list based on input array (made with ->parseFromTables())
-     *
-     * @param array $tablesArray Array of table names, (made with ->parseFromTables())
-     * @return string Table name string
-     * @see parseFromTables()
-     */
-    public function compileFromTables($tablesArray)
-    {
-        // Prepare buffer variable:
-        $outputParts = [];
-        // Traverse the table names:
-        if (is_array($tablesArray)) {
-            foreach ($tablesArray as $k => $v) {
-                // Set table name:
-                $outputParts[$k] = $v['table'];
-                // Add alias AS if there:
-                if ($v['as']) {
-                    $outputParts[$k] .= ' ' . $v['as_keyword'] . ' ' . $v['as'];
-                }
-                if (is_array($v['JOIN'])) {
-                    foreach ($v['JOIN'] as $join) {
-                        $outputParts[$k] .= ' ' . $join['type'] . ' ' . $join['withTable'];
-                        // Add alias AS if there:
-                        if (isset($join['as']) && $join['as']) {
-                            $outputParts[$k] .= ' ' . $join['as_keyword'] . ' ' . $join['as'];
-                        }
-                        $outputParts[$k] .= ' ON ';
-                        foreach ($join['ON'] as $condition) {
-                            if ($condition['operator'] !== '') {
-                                $outputParts[$k] .= ' ' . $condition['operator'] . ' ';
-                            }
-                            $outputParts[$k] .= $this->compileJoinIdentifier($condition['left']);
-                            $outputParts[$k] .= $condition['comparator'];
-                            if (!empty($condition['right']['value'])) {
-                                $value = $condition['right']['value'];
-                                $outputParts[$k] .= $value[1] . $this->compileAddslashes($value[0]) . $value[1];
-                            } else {
-                                $outputParts[$k] .= $this->compileJoinIdentifier($condition['right']);
-                            }
-                        }
-                    }
-                }
-            }
-        }
-        // Return imploded buffer:
-        return implode(', ', $outputParts);
-    }
-
-    /**
-     * Compiles a CASE ... WHEN flow-control construct based on input array (made with ->parseCaseStatement())
-     *
-     * @param array $components Array of case components, (made with ->parseCaseStatement())
-     * @param bool $functionMapping Whether function mapping should take place
-     * @return string case when string
-     * @see parseCaseStatement()
-     */
-    protected function compileCaseStatement(array $components, $functionMapping = true)
-    {
-        $statement = 'CASE';
-        if (isset($components['case_field'])) {
-            $statement .= ' ' . $components['case_field'];
-        } elseif (isset($components['case_value'])) {
-            $statement .= ' ' . $components['case_value'][1] . $components['case_value'][0] . $components['case_value'][1];
-        }
-        foreach ($components['when'] as $when) {
-            $statement .= ' WHEN ';
-            $statement .= $this->compileWhereClause($when['when_value'], $functionMapping);
-            $statement .= ' THEN ';
-            $statement .= $when['then_value'][1] . $when['then_value'][0] . $when['then_value'][1];
-        }
-        if (isset($components['else'])) {
-            $statement .= ' ELSE ';
-            $statement .= $components['else'][1] . $components['else'][0] . $components['else'][1];
-        }
-        $statement .= ' END';
-        return $statement;
-    }
-}
diff --git a/typo3/sysext/dbal/Classes/Database/SqlCompilers/Adodb.php b/typo3/sysext/dbal/Classes/Database/SqlCompilers/Adodb.php
deleted file mode 100644 (file)
index 846731a..0000000
+++ /dev/null
@@ -1,609 +0,0 @@
-<?php
-namespace TYPO3\CMS\Dbal\Database\SqlCompilers;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * 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.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-use TYPO3\CMS\Core\Charset\CharsetConverter;
-use TYPO3\CMS\Core\Utility\GeneralUtility;
-use TYPO3\CMS\Dbal\Database\Specifics;
-use TYPO3\CMS\Dbal\Database\SqlParser;
-
-/**
- * SQL Compiler for ADOdb connections
- */
-class Adodb extends AbstractCompiler
-{
-    /**
-     * Compiles an INSERT statement from components array
-     *
-     * @param array Array of SQL query components
-     * @return string SQL INSERT query / array
-     * @see parseINSERT()
-     */
-    protected function compileINSERT($components)
-    {
-        $values = [];
-        if (isset($components['VALUES_ONLY']) && is_array($components['VALUES_ONLY'])) {
-            $valuesComponents = $components['EXTENDED'] === '1' ? $components['VALUES_ONLY'] : [$components['VALUES_ONLY']];
-            $tableFields = array_keys($this->databaseConnection->cache_fieldType[$components['TABLE']]);
-        } else {
-            $valuesComponents = $components['EXTENDED'] === '1' ? $components['FIELDS'] : [$components['FIELDS']];
-            $tableFields = array_keys($valuesComponents[0]);
-        }
-        foreach ($valuesComponents as $valuesComponent) {
-            $fields = [];
-            $fc = 0;
-            foreach ($valuesComponent as $fV) {
-                $fields[$tableFields[$fc++]] = $fV[0];
-            }
-            $values[] = $fields;
-        }
-        return count($values) === 1 ? $values[0] : $values;
-    }
-
-    /**
-     * Compiles a CREATE TABLE statement from components array
-     *
-     * @param array $components Array of SQL query components
-     * @return array array with SQL CREATE TABLE/INDEX command(s)
-     * @see parseCREATETABLE()
-     */
-    protected function compileCREATETABLE($components)
-    {
-        // Create fields and keys:
-        $fieldsKeys = [];
-        $indexKeys = [];
-        foreach ($components['FIELDS'] as $fN => $fCfg) {
-            $handlerKey = $this->databaseConnection->handler_getFromTableList($components['TABLE']);
-            $fieldsKeys[$fN] = $this->databaseConnection->quoteName($fN, $handlerKey, true) . ' ' . $this->compileFieldCfg($fCfg['definition']);
-        }
-        if (isset($components['KEYS']) && is_array($components['KEYS'])) {
-            foreach ($components['KEYS'] as $kN => $kCfg) {
-                if ($kN === 'PRIMARYKEY') {
-                    foreach ($kCfg as $field) {
-                        $fieldsKeys[$field] .= ' PRIMARY';
-                    }
-                } elseif ($kN === 'UNIQUE') {
-                    foreach ($kCfg as $n => $field) {
-                        $indexKeys = array_merge($indexKeys, $this->compileCREATEINDEX($n, $components['TABLE'], $field, ['UNIQUE']));
-                    }
-                } else {
-                    $indexKeys = array_merge($indexKeys, $this->compileCREATEINDEX($kN, $components['TABLE'], $kCfg));
-                }
-            }
-        }
-        // Generally create without OID on PostgreSQL
-        $tableOptions = ['postgres' => 'WITHOUT OIDS'];
-        // Fetch table/index generation query:
-        $tableName = $this->databaseConnection->quoteName($components['TABLE'], null, true);
-        $query = array_merge($this->databaseConnection->handlerInstance[$this->databaseConnection->lastHandlerKey]->DataDictionary->CreateTableSQL($tableName, implode(',' . LF, $fieldsKeys), $tableOptions), $indexKeys);
-        return $query;
-    }
-
-    /**
-     * Compiles an ALTER TABLE statement from components array
-     *
-     * @param array Array of SQL query components
-     * @return string SQL ALTER TABLE query
-     * @see parseALTERTABLE()
-     */
-    protected function compileALTERTABLE($components)
-    {
-        $query = '';
-        $tableName = $this->databaseConnection->quoteName($components['TABLE'], null, true);
-        $fieldName = $this->databaseConnection->quoteName($components['FIELD'], null, true);
-        switch (strtoupper(str_replace([' ', "\n", "\r", "\t"], '', $components['action']))) {
-            case 'ADD':
-                $query = $this->databaseConnection->handlerInstance[$this->databaseConnection->lastHandlerKey]->DataDictionary->AddColumnSQL($tableName, $fieldName . ' ' . $this->compileFieldCfg($components['definition']));
-                break;
-            case 'CHANGE':
-                $query = $this->databaseConnection->handlerInstance[$this->databaseConnection->lastHandlerKey]->DataDictionary->AlterColumnSQL($tableName, $fieldName . ' ' . $this->compileFieldCfg($components['definition']));
-                break;
-            case 'RENAME':
-                $query = $this->databaseConnection->handlerInstance[$this->databaseConnection->lastHandlerKey]->DataDictionary->RenameTableSQL($tableName, $fieldName);
-                break;
-            case 'DROP':
-
-            case 'DROPKEY':
-                $query = $this->compileDROPINDEX($components['KEY'], $components['TABLE']);
-                break;
-
-            case 'ADDKEY':
-                $query = $this->compileCREATEINDEX($components['KEY'], $components['TABLE'], $components['fields']);
-                break;
-            case 'ADDUNIQUE':
-                $query = $this->compileCREATEINDEX($components['KEY'], $components['TABLE'], $components['fields'], ['UNIQUE']);
-                break;
-            case 'ADDPRIMARYKEY':
-                // @todo ???
-                break;
-            case 'DEFAULTCHARACTERSET':
-
-            case 'ENGINE':
-                // @todo ???
-                break;
-        }
-        return $query;
-    }
-
-    /**
-     * Compiles CREATE INDEX statements from component information
-     *
-     * MySQL only needs uniqueness of index names per table, but many DBMS require uniqueness of index names per schema.
-     * The table name is hashed and prepended to the index name to make sure index names are unique.
-     *
-     * @param string $indexName
-     * @param string $tableName
-     * @param array $indexFields
-     * @param array $indexOptions
-     * @return array
-     * @see compileALTERTABLE()
-     */
-    protected function compileCREATEINDEX($indexName, $tableName, $indexFields, $indexOptions = [])
-    {
-        $indexIdentifier = $this->databaseConnection->quoteName(hash('crc32b', $tableName) . '_' . $indexName, null, true);
-        $dbmsSpecifics = $this->databaseConnection->getSpecifics();
-        $keepFieldLengths = $dbmsSpecifics->specificExists(Specifics\AbstractSpecifics::PARTIAL_STRING_INDEX) && $dbmsSpecifics->getSpecific(Specifics\AbstractSpecifics::PARTIAL_STRING_INDEX);
-
-        foreach ($indexFields as $key => $fieldName) {
-            if (!$keepFieldLengths) {
-                $fieldName = preg_replace('/\A([^\(]+)(\(\d+\))/', '\\1', $fieldName);
-            }
-            // Quote the fieldName in backticks with escaping, ADOdb will replace the backticks with the correct quoting
-            $indexFields[$key] = '`' . str_replace('`', '``', $fieldName) . '`';
-        }
-
-        return $this->databaseConnection->handlerInstance[$this->databaseConnection->handler_getFromTableList($tableName)]->DataDictionary->CreateIndexSQL(
-            $indexIdentifier, $this->databaseConnection->quoteName($tableName, null, true), $indexFields, $indexOptions
-        );
-    }
-
-    /**
-     * Compiles DROP INDEX statements from component information
-     *
-     * MySQL only needs uniqueness of index names per table, but many DBMS require uniqueness of index names per schema.
-     * The table name is hashed and prepended to the index name to make sure index names are unique.
-     *
-     * @param $indexName
-     * @param $tableName
-     * @return array
-     * @see compileALTERTABLE()
-     */
-    protected function compileDROPINDEX($indexName, $tableName)
-    {
-        $indexIdentifier = $this->databaseConnection->quoteName(hash('crc32b', $tableName) . '_' . $indexName, null, true);
-
-        return $this->databaseConnection->handlerInstance[$this->databaseConnection->handler_getFromTableList($tableName)]->DataDictionary->DropIndexSQL(
-            $indexIdentifier, $this->databaseConnection->quoteName($tableName)
-        );
-    }
-
-    /**
-     * Compiles a "SELECT [output] FROM..:" field list based on input array (made with ->parseFieldList())
-     * Can also compile field lists for ORDER BY and GROUP BY.
-     *
-     * @param array $selectFields Array of select fields, (made with ->parseFieldList())
-     * @param bool $compileComments Whether comments should be compiled
-     * @param bool $functionMapping Whether function mapping should take place
-     * @return string Select field string
-     * @see parseFieldList()
-     */
-    public function compileFieldList($selectFields, $compileComments = true, $functionMapping = true)
-    {
-        $output = '';
-        // Traverse the selectFields if any:
-        if (is_array($selectFields)) {
-            $outputParts = [];
-            foreach ($selectFields as $k => $v) {
-                // Detecting type:
-                switch ($v['type']) {
-                    case 'function':
-                        $outputParts[$k] = $v['function'] . '(' . $v['func_content'] . ')';
-                        break;
-                    case 'flow-control':
-                        if ($v['flow-control']['type'] === 'CASE') {
-                            $outputParts[$k] = $this->compileCaseStatement($v['flow-control'], $functionMapping);
-                        }
-                        break;
-                    case 'field':
-                        $outputParts[$k] = ($v['distinct'] ? $v['distinct'] : '') . ($v['table'] ? $v['table'] . '.' : '') . $v['field'];
-                        break;
-                }
-                // Alias:
-                if ($v['as']) {
-                    $outputParts[$k] .= ' ' . $v['as_keyword'] . ' ' . $v['as'];
-                }
-                // Specifically for ORDER BY and GROUP BY field lists:
-                if ($v['sortDir']) {
-                    $outputParts[$k] .= ' ' . $v['sortDir'];
-                }
-            }
-            // @todo Handle SQL hints in comments according to current DBMS
-            if (false && $selectFields[0]['comments']) {
-                $output = $selectFields[0]['comments'] . ' ';
-            }
-            $output .= implode(', ', $outputParts);
-        }
-        return $output;
-    }
-
-    /**
-     * Add slashes function used for compiling queries
-     * This method overrides the method from \TYPO3\CMS\Dbal\Database\NativeSqlParser because
-     * the input string is already properly escaped.
-     *
-     * @param string $str Input string
-     * @return string Output string
-     */
-    protected function compileAddslashes($str)
-    {
-        return $str;
-    }
-
-    /**
-     * Compile field definition
-     *
-     * @param array $fieldCfg Field definition parts
-     * @return string Field definition string
-     */
-    protected function compileFieldCfg($fieldCfg)
-    {
-        // Set type:
-        $type = $this->databaseConnection->getSpecifics()->getMetaFieldType($fieldCfg['fieldType']);
-        $cfg = $type;
-        // Add value, if any:
-        if ((string)$fieldCfg['value'] !== '' && in_array($type, ['C', 'C2'])) {
-            $cfg .= ' ' . $fieldCfg['value'];
-        } elseif (!isset($fieldCfg['value']) && in_array($type, ['C', 'C2'])) {
-            $cfg .= ' 255';
-        }
-        // Add additional features:
-        $noQuote = true;
-        if (is_array($fieldCfg['featureIndex'])) {
-            // MySQL assigns DEFAULT value automatically if NOT NULL, fake this here
-            // numeric fields get 0 as default, other fields an empty string
-            if (isset($fieldCfg['featureIndex']['NOTNULL']) && !isset($fieldCfg['featureIndex']['DEFAULT']) && !isset($fieldCfg['featureIndex']['AUTO_INCREMENT'])) {
-                switch ($type) {
-                    case 'I8':
-
-                    case 'F':
-
-                    case 'N':
-                        $fieldCfg['featureIndex']['DEFAULT'] = ['keyword' => 'DEFAULT', 'value' => ['0', '']];
-                        break;
-                    default:
-                        $fieldCfg['featureIndex']['DEFAULT'] = ['keyword' => 'DEFAULT', 'value' => ['', '\'']];
-                }
-            }
-            foreach ($fieldCfg['featureIndex'] as $feature => $featureDef) {
-                switch (true) {
-                    case $feature === 'UNSIGNED' && !$this->databaseConnection->runningADOdbDriver('mysql'):
-                    case $feature === 'NOTNULL' && $this->databaseConnection->runningADOdbDriver('oci8'):
-                        continue;
-                    case $feature === 'AUTO_INCREMENT':
-                        $cfg .= ' AUTOINCREMENT';
-                        break;
-                    case $feature === 'NOTNULL':
-                        $cfg .= ' NOTNULL';
-                        break;
-                    default:
-                        $cfg .= ' ' . $featureDef['keyword'];
-                }
-                // Add value if found:
-                if (is_array($featureDef['value'])) {
-                    if ($featureDef['value'][0] === '') {
-                        $cfg .= ' "\'\'"';
-                    } else {
-                        $cfg .= ' ' . $featureDef['value'][1] . $this->compileAddslashes($featureDef['value'][0]) . $featureDef['value'][1];
-                        if (!is_numeric($featureDef['value'][0])) {
-                            $noQuote = false;
-                        }
-                    }
-                }
-            }
-        }
-        if ($noQuote) {
-            $cfg .= ' NOQUOTE';
-        }
-        // Return field definition string:
-        return $cfg;
-    }
-
-    /**
-     * Implodes an array of WHERE clause configuration into a WHERE clause.
-     *
-     * DBAL-specific: The only(!) handled "calc" operators supported by parseWhereClause() are:
-     * - the bitwise logical and (&)
-     * - the addition (+)
-     * - the substraction (-)
-     * - the multiplication (*)
-     * - the division (/)
-     * - the modulo (%)
-     *
-     * @param array $clauseArray
-     * @param bool $functionMapping
-     * @return string WHERE clause as string.
-     * @see \TYPO3\CMS\Core\Database\SqlParser::parseWhereClause()
-     */
-    public function compileWhereClause($clauseArray, $functionMapping = true)
-    {
-        // Prepare buffer variable:
-        $output = '';
-        // Traverse clause array:
-        if (is_array($clauseArray)) {
-            foreach ($clauseArray as $v) {
-                // Set operator:
-                $output .= $v['operator'] ? ' ' . $v['operator'] : '';
-                // Look for sublevel:
-                if (is_array($v['sub'])) {
-                    $output .= ' (' . trim($this->compileWhereClause($v['sub'], $functionMapping)) . ')';
-                } elseif (isset($v['func']) && $v['func']['type'] === 'EXISTS') {
-                    $output .= ' ' . trim($v['modifier']) . ' EXISTS (' . $this->compileSELECT($v['func']['subquery']) . ')';
-                } else {
-                    if (isset($v['func']) && $v['func']['type'] === 'CAST') {
-                        $output .= ' ' . trim($v['modifier']);
-                        $output .= ' CAST(';
-                        $output .= ($v['func']['table'] ? $v['func']['table'] . '.' : '') . $v['func']['field'];
-                        $output .= ' AS ' . $v['func']['datatype'][0] . ')';
-                    } elseif (isset($v['func']) && $v['func']['type'] === 'LOCATE') {
-                        $output .= ' ' . trim($v['modifier']);
-                        switch (true) {
-                            case $this->databaseConnection->runningADOdbDriver('mssql') && $functionMapping:
-                                $output .= ' CHARINDEX(';
-                                $output .= $v['func']['substr'][1] . $v['func']['substr'][0] . $v['func']['substr'][1];
-                                $output .= ', ' . ($v['func']['table'] ? $v['func']['table'] . '.' : '') . $v['func']['field'];
-                                $output .= isset($v['func']['pos']) ? ', ' . $v['func']['pos'][0] : '';
-                                $output .= ')';
-                                break;
-                            case $this->databaseConnection->runningADOdbDriver('oci8') && $functionMapping:
-                                $output .= ' INSTR(';
-                                $output .= ($v['func']['table'] ? $v['func']['table'] . '.' : '') . $v['func']['field'];
-                                $output .= ', ' . $v['func']['substr'][1] . $v['func']['substr'][0] . $v['func']['substr'][1];
-                                $output .= isset($v['func']['pos']) ? ', ' . $v['func']['pos'][0] : '';
-                                $output .= ')';
-                                break;
-                            default:
-                                $output .= ' LOCATE(';
-                                $output .= $v['func']['substr'][1] . $v['func']['substr'][0] . $v['func']['substr'][1];
-                                $output .= ', ' . ($v['func']['table'] ? $v['func']['table'] . '.' : '') . $v['func']['field'];
-                                $output .= isset($v['func']['pos']) ? ', ' . $v['func']['pos'][0] : '';
-                                $output .= ')';
-                        }
-                    } elseif (isset($v['func']) && $v['func']['type'] === 'IFNULL') {
-                        $output .= ' ' . trim($v['modifier']) . ' ';
-                        switch (true) {
-                            case $this->databaseConnection->runningADOdbDriver('mssql') && $functionMapping:
-                                $output .= 'ISNULL';
-                                break;
-                            case $this->databaseConnection->runningADOdbDriver('oci8') && $functionMapping:
-                                $output .= 'NVL';
-                                break;
-                            default:
-                                $output .= 'IFNULL';
-                        }
-                        $output .= '(';
-                        $output .= ($v['func']['table'] ? $v['func']['table'] . '.' : '') . $v['func']['field'];
-                        $output .= ', ' . $v['func']['default'][1] . $this->compileAddslashes($v['func']['default'][0]) . $v['func']['default'][1];
-                        $output .= ')';
-                    } elseif (isset($v['func']) && $v['func']['type'] === 'FIND_IN_SET') {
-                        $output .= ' ' . trim($v['modifier']) . ' ';
-                        if ($functionMapping) {
-                            switch (true) {
-                                case $this->databaseConnection->runningADOdbDriver('mssql'):
-                                    $field = ($v['func']['table'] ? $v['func']['table'] . '.' : '') . $v['func']['field'];
-                                    if (!isset($v['func']['str_like'])) {
-                                        $v['func']['str_like'] = $v['func']['str'][0];
-                                    }
-                                    $output .= '\',\'+' . $field . '+\',\' LIKE \'%,' . $v['func']['str_like'] . ',%\'';
-                                    break;
-                                case $this->databaseConnection->runningADOdbDriver('oci8'):
-                                    $field = ($v['func']['table'] ? $v['func']['table'] . '.' : '') . $v['func']['field'];
-                                    if (!isset($v['func']['str_like'])) {
-                                        $v['func']['str_like'] = $v['func']['str'][0];
-                                    }
-                                    $output .= '\',\'||' . $field . '||\',\' LIKE \'%,' . $v['func']['str_like'] . ',%\'';
-                                    break;
-                                case $this->databaseConnection->runningADOdbDriver('postgres'):
-                                    $output .= ' FIND_IN_SET(';
-                                    $output .= $v['func']['str'][1] . $v['func']['str'][0] . $v['func']['str'][1];
-                                    $output .= ', ' . ($v['func']['table'] ? $v['func']['table'] . '.' : '') . $v['func']['field'];
-                                    $output .= ') != 0';
-                                    break;
-                                default:
-                                    $field = ($v['func']['table'] ? $v['func']['table'] . '.' : '') . $v['func']['field'];
-                                    if (!isset($v['func']['str_like'])) {
-                                        $v['func']['str_like'] = $v['func']['str'][0];
-                                    }
-                                    $output .= '(' . $field . ' LIKE \'%,' . $v['func']['str_like'] . ',%\'' . ' OR ' . $field . ' LIKE \'' . $v['func']['str_like'] . ',%\'' . ' OR ' . $field . ' LIKE \'%,' . $v['func']['str_like'] . '\'' . ' OR ' . $field . '= ' . $v['func']['str'][1] . $v['func']['str'][0] . $v['func']['str'][1] . ')';
-                            }
-                        } else {
-                            switch (true) {
-                                case $this->databaseConnection->runningADOdbDriver('mssql'):
-
-                                case $this->databaseConnection->runningADOdbDriver('oci8'):
-
-                                case $this->databaseConnection->runningADOdbDriver('postgres'):
-                                    $output .= ' FIND_IN_SET(';
-                                    $output .= $v['func']['str'][1] . $v['func']['str'][0] . $v['func']['str'][1];
-                                    $output .= ', ' . ($v['func']['table'] ? $v['func']['table'] . '.' : '') . $v['func']['field'];
-                                    $output .= ')';
-                                    break;
-                                default:
-                                    $field = ($v['func']['table'] ? $v['func']['table'] . '.' : '') . $v['func']['field'];
-                                    if (!isset($v['func']['str_like'])) {
-                                        $v['func']['str_like'] = $v['func']['str'][0];
-                                    }
-                                    $output .= '(' . $field . ' LIKE \'%,' . $v['func']['str_like'] . ',%\'' . ' OR ' . $field . ' LIKE \'' . $v['func']['str_like'] . ',%\'' . ' OR ' . $field . ' LIKE \'%,' . $v['func']['str_like'] . '\'' . ' OR ' . $field . '= ' . $v['func']['str'][1] . $v['func']['str'][0] . $v['func']['str'][1] . ')';
-                            }
-                        }
-                    } else {
-                        // Set field/table with modifying prefix if any:
-                        $output .= ' ' . trim($v['modifier']) . ' ';
-                        // DBAL-specific: Set calculation, if any:
-                        if ($v['calc'] === '&' && $functionMapping) {
-                            switch (true) {
-                                case $this->databaseConnection->runningADOdbDriver('oci8'):
-                                    // Oracle only knows BITAND(x,y) - sigh
-                                    $output .= 'BITAND(' . trim(($v['table'] ? $v['table'] . '.' : '') . $v['field']) . ',' . $v['calc_value'][1] . $this->compileAddslashes($v['calc_value'][0]) . $v['calc_value'][1] . ')';
-                                    break;
-                                default:
-                                    // MySQL, MS SQL Server, PostgreSQL support the &-syntax
-                                    $output .= trim(($v['table'] ? $v['table'] . '.' : '') . $v['field']) . $v['calc'] . $v['calc_value'][1] . $this->compileAddslashes($v['calc_value'][0]) . $v['calc_value'][1];
-                            }
-                        } elseif ($v['calc']) {
-                            $output .= trim(($v['table'] ? $v['table'] . '.' : '') . $v['field']) . $v['calc'];
-                            if (isset($v['calc_table'])) {
-                                $output .= trim(($v['calc_table'] ? $v['calc_table'] . '.' : '') . $v['calc_field']);
-                            } else {
-                                $output .= $v['calc_value'][1] . $this->compileAddslashes($v['calc_value'][0]) . $v['calc_value'][1];
-                            }
-                        } elseif (!($this->databaseConnection->runningADOdbDriver('oci8') && preg_match('/(NOT )?LIKE( BINARY)?/', $v['comparator']) && $functionMapping)) {
-                            $output .= trim(($v['table'] ? $v['table'] . '.' : '') . $v['field']);
-                        }
-                    }
-                    // Set comparator:
-                    if ($v['comparator']) {
-                        $isLikeOperator = preg_match('/(NOT )?LIKE( BINARY)?/', $v['comparator']);
-                        switch (true) {
-                            case $this->databaseConnection->runningADOdbDriver('oci8') && $isLikeOperator && $functionMapping:
-                                // Oracle cannot handle LIKE on CLOB fields - sigh
-                                if (isset($v['value']['operator'])) {
-                                    $values = [];
-                                    foreach ($v['value']['args'] as $fieldDef) {
-                                        $values[] = ($fieldDef['table'] ? $fieldDef['table'] . '.' : '') . $fieldDef['field'];
-                                    }
-                                    $compareValue = ' ' . $v['value']['operator'] . '(' . implode(',', $values) . ')';
-                                } else {
-                                    $compareValue = $v['value'][1] . $this->compileAddslashes(trim($v['value'][0], '%')) . $v['value'][1];
-                                }
-                                if (GeneralUtility::isFirstPartOfStr($v['comparator'], 'NOT')) {
-                                    $output .= 'NOT ';
-                                }
-                                // To be on the safe side
-                                $isLob = true;
-                                if ($v['table']) {
-                                    // Table and field names are quoted:
-                                    $tableName = substr($v['table'], 1, strlen($v['table']) - 2);
-                                    $fieldName = substr($v['field'], 1, strlen($v['field']) - 2);
-                                    $fieldType = $this->databaseConnection->sql_field_metatype($tableName, $fieldName);
-                                    $isLob = $fieldType === 'B' || $fieldType === 'XL';
-                                }
-                                if (strtoupper(substr($v['comparator'], -6)) === 'BINARY') {
-                                    if ($isLob) {
-                                        $output .= '(dbms_lob.instr(' . trim(($v['table'] ? $v['table'] . '.' : '') . $v['field']) . ', ' . $compareValue . ',1,1) > 0)';
-                                    } else {
-                                        $output .= '(instr(' . trim((($v['table'] ? $v['table'] . '.' : '') . $v['field'])) . ', ' . $compareValue . ',1,1) > 0)';
-                                    }
-                                } else {
-                                    $charsetConverter = GeneralUtility::makeInstance(CharsetConverter::class);
-                                    if ($isLob) {
-                                        $output .= '(dbms_lob.instr(LOWER(' . trim(($v['table'] ? $v['table'] . '.' : '') . $v['field']) . '), ' . $charsetConverter->conv_case('utf-8', $compareValue, 'toLower') . ',1,1) > 0)';
-                                    } else {
-                                        $output .= '(instr(LOWER(' . trim(($v['table'] ? $v['table'] . '.' : '') . $v['field']) . '), ' . $charsetConverter->conv_case('utf-8', $compareValue, 'toLower') . ',1,1) > 0)';
-                                    }
-                                }
-                                break;
-                            default:
-                                if ($isLikeOperator && $functionMapping) {
-                                    if ($this->databaseConnection->runningADOdbDriver('postgres') || $this->databaseConnection->runningADOdbDriver('postgres64') || $this->databaseConnection->runningADOdbDriver('postgres7') ||&