TYPO3 API  SVNRelease
class.ux_t3lib_db.php
Go to the documentation of this file.
00001 <?php
00002 /***************************************************************
00003  *  Copyright notice
00004  *
00005  *  (c) 2004-2009 Kasper Skårhøj (kasperYYYY@typo3.com)
00006  *  (c) 2004-2009 Karsten Dambekalns <karsten@typo3.org>
00007  *  (c) 2009-2010 Xavier Perseguers <typo3@perseguers.ch>
00008  *  All rights reserved
00009  *
00010  *  This script is part of the TYPO3 project. The TYPO3 project is
00011  *  free software; you can redistribute it and/or modify
00012  *  it under the terms of the GNU General Public License as published by
00013  *  the Free Software Foundation; either version 2 of the License, or
00014  *  (at your option) any later version.
00015  *
00016  *  The GNU General Public License can be found at
00017  *  http://www.gnu.org/copyleft/gpl.html.
00018  *  A copy is found in the textfile GPL.txt and important notices to the license
00019  *  from the author is found in LICENSE.txt distributed with these scripts.
00020  *
00021  *
00022  *  This script is distributed in the hope that it will be useful,
00023  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00024  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00025  *  GNU General Public License for more details.
00026  *
00027  *  This copyright notice MUST APPEAR in all copies of the script!
00028  ***************************************************************/
00029 /**
00030  * Contains a database abstraction layer class for TYPO3
00031  *
00032  * $Id: class.ux_t3lib_db.php 42596 2011-01-25 20:02:07Z xperseguers $
00033  *
00034  * @author  Kasper Skårhøj <kasper@typo3.com>
00035  * @author  Karsten Dambekalns <k.dambekalns@fishfarm.de>
00036  * @author  Xavier Perseguers <typo3@perseguers.ch>
00037  */
00038 /**
00039  * [CLASS/FUNCTION INDEX of SCRIPT]
00040  *
00041  *
00042  *
00043  *  161: class ux_t3lib_DB extends t3lib_DB
00044  *  229:     public function __construct()
00045  *  260:     protected function initInternalVariables()
00046  *  283:     public function clearCachedFieldInfo()
00047  *  294:     public function cacheFieldInfo()
00048  *  342:     protected function analyzeFields($parsedExtSQL)
00049  *  375:     protected function mapCachedFieldInfo($fieldInfo)
00050  *
00051  *            SECTION: Query Building (Overriding parent methods)
00052  *  438:     public function exec_INSERTquery($table, $fields_values, $no_quote_fields = '')
00053  *  575:     public function exec_INSERTmultipleRows($table, array $fields, array $rows, $no_quote_fields = FALSE)
00054  *  600:     public function exec_UPDATEquery($table,$where,$fields_values,$no_quote_fields = '')
00055  *  692:     public function exec_DELETEquery($table, $where)
00056  *  759:     public function exec_SELECTquery($select_fields, $from_table, $where_clause, $groupBy = '', $orderBy = '', $limit = '')
00057  *  856:     public function exec_TRUNCATEquery($table)
00058  *  914:     protected function exec_query(array $queryParts)
00059  *
00060  *            SECTION: Query building
00061  *  978:     public function INSERTquery($table, $fields_values, $no_quote_fields = '')
00062  * 1052:     public function INSERTmultipleRows($table, array $fields, array $rows, $no_quote_fields = FALSE)
00063  * 1085:     public function UPDATEquery($table, $where, $fields_values, $no_quote_fields = '')
00064  * 1170:     public function DELETEquery($table, $where)
00065  * 1196:     public function SELECTquery($select_fields, $from_table, $where_clause, $groupBy = '', $orderBy = '', $limit = '')
00066  * 1229:     protected function SELECTqueryFromArray(array $params)
00067  * 1267:     protected function compileSelectParameters(array $params)
00068  * 1283:     public function TRUNCATEquery($table)
00069  *
00070  *            SECTION: Prepared Query Support
00071  * 1314:     public function prepare_SELECTquery($select_fields, $from_table, $where_clause, $groupBy = '', $orderBy = '', $limit = '', array $input_parameters = array())
00072  * 1416:     protected function getQueryComponents($select_fields, $from_table, $where_clause, $groupBy, $orderBy, $limit)
00073  * 1465:     protected function precompileSELECTquery(array $components)
00074  * 1523:     public function exec_PREPAREDquery($query, array $precompiledParts)
00075  *
00076  *            SECTION: Functions for quoting table/field names
00077  * 1619:     protected function quoteSELECTsubquery(array $components)
00078  * 1634:     public function quoteSelectFields($select_fields)
00079  * 1644:     public function quoteFieldNames($select_fields)
00080  * 1664:     protected function _quoteFieldNames(array $select_fields)
00081  * 1701:     public function quoteFromTables($from_table)
00082  * 1717:     protected function _quoteFromTables(array $from_table)
00083  * 1746:     public function quoteWhereClause($where_clause)
00084  * 1767:     protected function _quoteWhereClause(array $where_clause)
00085  * 1843:     protected function quoteGroupBy($groupBy)
00086  * 1860:     protected function _quoteGroupBy(array $groupBy)
00087  * 1877:     protected function quoteOrderBy($orderBy)
00088  * 1894:     protected function _quoteOrderBy(array $orderBy)
00089  *
00090  *            SECTION: Various helper functions
00091  * 1919:     public function fullQuoteStr($str, $table)
00092  * 1932:     public function quoteStr($str, $table)
00093  * 1965:     public function quoteName($name, $handlerKey = NULL, $useBackticks = FALSE)
00094  * 1984:     public function MetaType($type, $table, $max_length = -1)
00095  * 2015:     public function MySQLMetaType($t)
00096  * 2062:     public function MySQLActualType($meta)
00097  *
00098  *            SECTION: SQL wrapper functions (Overriding parent methods)
00099  * 2105:     public function sql_error()
00100  * 2125:     public function sql_errno()
00101  * 2146:     public function sql_num_rows(&$res)
00102  * 2170:     public function sql_fetch_assoc(&$res)
00103  * 2233:     public function sql_fetch_row(&$res)
00104  * 2279:     public function sql_free_result(&$res)
00105  * 2308:     public function sql_insert_id()
00106  * 2328:     public function sql_affected_rows()
00107  * 2350:     public function sql_data_seek(&$res, $seek)
00108  * 2375:     public function sql_field_metatype($table, $field)
00109  * 2405:     public function sql_field_type(&$res,$pointer)
00110  *
00111  *            SECTION: Legacy functions, bound to _DEFAULT handler. (Overriding parent methods)
00112  * 2459:     public function sql($db,$query)
00113  * 2477:     public function sql_query($query)
00114  * 2516:     public function sql_pconnect($TYPO3_db_host, $TYPO3_db_username, $TYPO3_db_password)
00115  * 2534:     public function sql_select_db($TYPO3_db)
00116  *
00117  *            SECTION: SQL admin functions
00118  * 2566:     public function admin_get_dbs()
00119  * 2607:     public function admin_get_tables()
00120  * 2673:     public function admin_get_fields($tableName)
00121  * 2742:     public function admin_get_keys($tableName)
00122  * 2847:     public function admin_get_charsets()
00123  * 2857:     public function admin_query($query)
00124  *
00125  *            SECTION: Handler management
00126  * 2941:     public function handler_getFromTableList($tableList)
00127  * 2989:     public function handler_init($handlerKey)
00128  * 3107:     public function isConnected()
00129  * 3127:     public function runningNative()
00130  * 3138:     public function runningADOdbDriver($driver)
00131  *
00132  *            SECTION: Table/Field mapping
00133  * 3165:     protected function map_needMapping($tableList, $fieldMappingOnly = FALSE, array &$parsedTableList = array())
00134  * 3215:     protected function map_assocArray($input, $tables, $rev = FALSE)
00135  * 3263:     protected function map_remapSELECTQueryParts($select_fields, $from_table, $where_clause, $groupBy, $orderBy)
00136  * 3357:     protected function getMappingKey($tableName)
00137  * 3371:     protected function getFreeMappingKey($tableName)
00138  * 3387:     protected function map_sqlParts(&$sqlPartArray, $defaultTable)
00139  * 3549:     protected function map_subquery(&$parsedQuery)
00140  * 3589:     protected function map_genericQueryParsed(&$parsedQuery)
00141  * 3654:     protected function map_fieldNamesInArray($table,&$fieldArray)
00142  *
00143  *            SECTION: Debugging
00144  * 3695:     public function debugHandler($function,$execTime,$inData)
00145  * 3790:     public function debug_WHERE($table, $where, $script = '')
00146  * 3813:     public function debug_log($query,$ms,$data,$join,$errorFlag, $script='')
00147  * 3846:     public function debug_explain($query)
00148  *
00149  * TOTAL FUNCTIONS: 82
00150  * (This index is automatically created/updated by the extension "extdeveval")
00151  *
00152  */
00153 /**
00154  * TYPO3 database abstraction layer
00155  *
00156  * @author  Kasper Skårhøj <kasper@typo3.com>
00157  * @author  Karsten Dambekalns <k.dambekalns@fishfarm.de>
00158  * @package TYPO3
00159  * @subpackage tx_dbal
00160  */
00161 class ux_t3lib_DB extends t3lib_DB {
00162 
00163     // Internal, static:
00164     var $printErrors = FALSE; // Enable output of SQL errors after query executions. Set through TYPO3_CONF_VARS, see init()
00165     var $debug = FALSE; // Enable debug mode. Set through TYPO3_CONF_VARS, see init()
00166     var $conf = array(); // Configuration array, copied from TYPO3_CONF_VARS in constructor.
00167 
00168     var $mapping = array(); // See manual.
00169     var $table2handlerKeys = array(); // See manual.
00170     var $handlerCfg = array( // See manual.
00171         '_DEFAULT' => array(
00172             'type' => 'native',
00173             'config' => array(
00174                 'username' => '', // Set by default (overridden)
00175                 'password' => '', // Set by default (overridden)
00176                 'host' => '', // Set by default (overridden)
00177                 'database' => '', // Set by default (overridden)
00178                 'driver' => '', // ONLY "adodb" type; eg. "mysql"
00179                 'sequenceStart' => 1, // ONLY "adodb", first number in sequences/serials/...
00180                 'useNameQuote' => 0 // ONLY "adodb", whether to use NameQuote() method from ADOdb to quote names
00181             )
00182         ),
00183     );
00184 
00185 
00186     // Internal, dynamic:
00187     var $handlerInstance = array(); // Contains instance of the handler objects as they are created. Exception is the native mySQL calls which are registered as an array with keys "handlerType" = "native" and "link" pointing to the link resource for the connection.
00188     var $lastHandlerKey = ''; // Storage of the handler key of last ( SELECT) query - used for subsequent fetch-row calls etc.
00189     var $lastQuery = ''; // Storage of last SELECT query
00190     var $lastParsedAndMappedQueryArray = array(); // Query array, the last one parsed
00191 
00192     var $resourceIdToTableNameMap = array(); // Mapping of resource ids to table names.
00193 
00194     // Internal, caching:
00195     var $cache_handlerKeyFromTableList = array(); // Caching handlerKeys for table lists
00196     var $cache_mappingFromTableList = array(); // Caching mapping information for table lists
00197     var $cache_autoIncFields = array(); // parsed SQL from standard DB dump file
00198     var $cache_fieldType = array(); // field types for tables/fields
00199     var $cache_primaryKeys = array(); // primary keys
00200 
00201     /**
00202      * SQL parser
00203      *
00204      * @var tx_dbal_sqlengine
00205      */
00206     var $SQLparser;
00207 
00208     /**
00209      * Installer
00210      *
00211      * @var t3lib_install
00212      */
00213     var $Installer;
00214 
00215     /**
00216      * Cache for queries
00217      *
00218      * @var t3lib_cache_frontend_VariableFrontend
00219      */
00220     protected $queryCache;
00221 
00222 
00223     /**
00224      * Constructor.
00225      * Creates SQL parser object and imports configuration from $TYPO3_CONF_VARS['EXTCONF']['dbal']
00226      */
00227     public function __construct() {
00228         // Set SQL parser object for internal use:
00229         $this->SQLparser = t3lib_div::makeInstance('tx_dbal_sqlengine');
00230         $this->Installer = t3lib_div::makeInstance('t3lib_install');
00231 
00232         if (TYPO3_UseCachingFramework) {
00233             tx_dbal_querycache::initializeCachingFramework();
00234 
00235             try {
00236                 $this->queryCache = $GLOBALS['typo3CacheManager']->getCache(
00237                     'dbal'
00238                 );
00239             } catch (t3lib_cache_exception_NoSuchCache $e) {
00240                 tx_dbal_querycache::initDbalCache();
00241 
00242                 $this->queryCache = $GLOBALS['typo3CacheManager']->getCache(
00243                     'dbal'
00244                 );
00245             }
00246         }
00247 
00248         // Set internal variables with configuration:
00249         $this->conf = $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['dbal'];
00250         $this->initInternalVariables();
00251     }
00252 
00253     /**
00254      * Setting internal variables from $this->conf.
00255      *
00256      * @return  void
00257      */
00258     protected function initInternalVariables() {
00259         // Set outside configuration:
00260         if (isset($this->conf['mapping'])) {
00261             $this->mapping = $this->conf['mapping'];
00262         }
00263         if (isset($this->conf['table2handlerKeys'])) {
00264             $this->table2handlerKeys = $this->conf['table2handlerKeys'];
00265         }
00266         if (isset($this->conf['handlerCfg'])) {
00267             $this->handlerCfg = $this->conf['handlerCfg'];
00268         }
00269 
00270         $this->cacheFieldInfo();
00271         // Debugging settings:
00272         $this->printErrors = $this->conf['debugOptions']['printErrors'] ? TRUE : FALSE;
00273         $this->debug = $this->conf['debugOptions']['enabled'] ? TRUE : FALSE;
00274     }
00275 
00276     /**
00277      * Clears the cached field information file.
00278      *
00279      * @return void
00280      */
00281     public function clearCachedFieldInfo() {
00282         if (file_exists(PATH_typo3conf . 'temp_fieldInfo.php')) {
00283             unlink(PATH_typo3conf . 'temp_fieldInfo.php');
00284         }
00285     }
00286 
00287     /**
00288      * Caches the field information.
00289      *
00290      * @return void
00291      */
00292     public function cacheFieldInfo() {
00293         $extSQL = '';
00294         $parsedExtSQL = array();
00295 
00296         // try to fetch cached file first
00297         // file is removed when admin_query() is called
00298         if (file_exists(PATH_typo3conf . 'temp_fieldInfo.php')) {
00299             $fdata = unserialize(t3lib_div::getUrl(PATH_typo3conf . 'temp_fieldInfo.php'));
00300             $this->cache_autoIncFields = $fdata['incFields'];
00301             $this->cache_fieldType = $fdata['fieldTypes'];
00302             $this->cache_primaryKeys = $fdata['primaryKeys'];
00303         } else {
00304             // handle stddb.sql, parse and analyze
00305             $extSQL = t3lib_div::getUrl(PATH_site . 't3lib/stddb/tables.sql');
00306             $parsedExtSQL = $this->Installer->getFieldDefinitions_fileContent($extSQL);
00307             $this->analyzeFields($parsedExtSQL);
00308 
00309             // loop over all installed extensions
00310             foreach ($GLOBALS['TYPO3_LOADED_EXT'] as $ext => $v) {
00311                 if (!is_array($v) || !isset($v['ext_tables.sql'])) {
00312                     continue;
00313                 }
00314 
00315                 // fetch db dump (if any) and parse it, then analyze
00316                 $extSQL = t3lib_div::getUrl($v['ext_tables.sql']);
00317                 $parsedExtSQL = $this->Installer->getFieldDefinitions_fileContent($extSQL);
00318                 $this->analyzeFields($parsedExtSQL);
00319             }
00320 
00321             $cachedFieldInfo = array('incFields' => $this->cache_autoIncFields, 'fieldTypes' => $this->cache_fieldType, 'primaryKeys' => $this->cache_primaryKeys);
00322             $cachedFieldInfo = serialize($this->mapCachedFieldInfo($cachedFieldInfo));
00323 
00324             // write serialized content to file
00325             t3lib_div::writeFile(PATH_typo3conf . 'temp_fieldInfo.php', $cachedFieldInfo);
00326 
00327             if (strcmp(t3lib_div::getUrl(PATH_typo3conf . 'temp_fieldInfo.php'), $cachedFieldInfo)) {
00328                 die('typo3conf/temp_fieldInfo.php was NOT updated properly (written content didn\'t match file content) - maybe write access problem?');
00329             }
00330         }
00331     }
00332 
00333     /**
00334      * Analyzes fields and adds the extracted information to the field type, auto increment and primary key info caches.
00335      *
00336      * @param array $parsedExtSQL The output produced by t3lib_install::getFieldDefinitions_fileContent()
00337      * @return void
00338      * @see t3lib_install::getFieldDefinitions_fileContent()
00339      */
00340     protected function analyzeFields($parsedExtSQL) {
00341         foreach ($parsedExtSQL as $table => $tdef) {
00342             if (is_array($tdef['fields'])) {
00343                 foreach ($tdef['fields'] as $field => $fdef) {
00344                     $fdef = $this->SQLparser->parseFieldDef($fdef);
00345                     $this->cache_fieldType[$table][$field]['type'] = $fdef['fieldType'];
00346                     $this->cache_fieldType[$table][$field]['metaType'] = $this->MySQLMetaType($fdef['fieldType']);
00347                     $this->cache_fieldType[$table][$field]['notnull'] = (isset($fdef['featureIndex']['NOTNULL']) && !$this->SQLparser->checkEmptyDefaultValue($fdef['featureIndex'])) ? 1 : 0;
00348                     if (isset($fdef['featureIndex']['DEFAULT'])) {
00349                         $default = $fdef['featureIndex']['DEFAULT']['value'][0];
00350                         if (isset($fdef['featureIndex']['DEFAULT']['value'][1])) {
00351                             $default = $fdef['featureIndex']['DEFAULT']['value'][1] . $default . $fdef['featureIndex']['DEFAULT']['value'][1];
00352                         }
00353                         $this->cache_fieldType[$table][$field]['default'] = $default;
00354                     }
00355                     if (isset($fdef['featureIndex']['AUTO_INCREMENT'])) {
00356                         $this->cache_autoIncFields[$table] = $field;
00357                     }
00358                     if (isset($tdef['keys']['PRIMARY'])) {
00359                         $this->cache_primaryKeys[$table] = substr($tdef['keys']['PRIMARY'], 13, -1);
00360                     }
00361                 }
00362             }
00363         }
00364     }
00365 
00366     /**
00367      * This function builds all definitions for mapped tables and fields
00368      * @see cacheFieldInfo()
00369      */
00370     protected function mapCachedFieldInfo($fieldInfo) {
00371         if (is_array($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['dbal']['mapping'])) {
00372             foreach ($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['dbal']['mapping'] as $mappedTable => $mappedConf) {
00373                 if (array_key_exists($mappedTable, $fieldInfo['incFields'])) {
00374                     $mappedTableAlias = $mappedConf['mapTableName'];
00375                     if (isset($mappedConf['mapFieldNames'][$fieldInfo['incFields'][$mappedTable]])) {
00376                         $fieldInfo['incFields'][$mappedTableAlias] = $mappedConf['mapFieldNames'][$fieldInfo['incFields'][$mappedTable]];
00377                     } else {
00378                         $fieldInfo['incFields'][$mappedTableAlias] = $fieldInfo['incFields'][$mappedTable];
00379                     }
00380                 }
00381 
00382                 if (array_key_exists($mappedTable, $fieldInfo['fieldTypes'])) {
00383                     foreach ($fieldInfo['fieldTypes'][$mappedTable] as $field => $fieldConf) {
00384                         $tempMappedFieldConf[$mappedConf['mapFieldNames'][$field]] = $fieldConf;
00385                     }
00386 
00387                     $fieldInfo['fieldTypes'][$mappedConf['mapTableName']] = $tempMappedFieldConf;
00388                 }
00389 
00390                 if (array_key_exists($mappedTable, $fieldInfo['primaryKeys'])) {
00391                     $mappedTableAlias = $mappedConf['mapTableName'];
00392                     if (isset($mappedConf['mapFieldNames'][$fieldInfo['primaryKeys'][$mappedTable]])) {
00393                         $fieldInfo['primaryKeys'][$mappedTableAlias] = $mappedConf['mapFieldNames'][$fieldInfo['primaryKeys'][$mappedTable]];
00394                     } else {
00395                         $fieldInfo['primaryKeys'][$mappedTableAlias] = $fieldInfo['primaryKeys'][$mappedTable];
00396                     }
00397                 }
00398             }
00399         }
00400 
00401         return $fieldInfo;
00402     }
00403 
00404 
00405     /************************************
00406      *
00407      * Query Building (Overriding parent methods)
00408      * These functions are extending counterparts in the parent class.
00409      *
00410      **************************************/
00411 
00412     /* From the ADOdb documentation, this is what we do (_Execute for SELECT, _query for the other actions)
00413 
00414     Execute() is the default way to run queries. You can use the low-level functions _Execute() and _query() to reduce query overhead.
00415     Both these functions share the same parameters as Execute().
00416 
00417     If you do not have any bind parameters or your database supports binding (without emulation), then you can call _Execute() directly.
00418     Calling this function bypasses bind emulation. Debugging is still supported in _Execute().
00419 
00420     If you do not require debugging facilities nor emulated binding, and do not require a recordset to be returned, then you can call _query.
00421     This is great for inserts, updates and deletes. Calling this function bypasses emulated binding, debugging, and recordset handling. Either
00422     the resultid, TRUE or FALSE are returned by _query().
00423     */
00424 
00425     /**
00426      * Inserts a record for $table from the array with field/value pairs $fields_values.
00427      *
00428      * @param   string      Table name
00429      * @param   array       Field values as key=>value pairs. Values will be escaped internally. Typically you would fill an array like "$insertFields" with 'fieldname'=>'value' and pass it to this function as argument.
00430      * @param mixed List/array of keys NOT to quote (eg. SQL functions)
00431      * @return  mixed       Result from handler, usually TRUE when success and FALSE on failure
00432      */
00433     public function exec_INSERTquery($table, $fields_values, $no_quote_fields = '') {
00434 
00435         if ($this->debug) {
00436             $pt = t3lib_div::milliseconds();
00437         }
00438 
00439         // Do field mapping if needed:
00440         $ORIG_tableName = $table;
00441         if ($tableArray = $this->map_needMapping($table)) {
00442 
00443             // Field mapping of array:
00444             $fields_values = $this->map_assocArray($fields_values, $tableArray);
00445 
00446             // Table name:
00447             if ($this->mapping[$table]['mapTableName']) {
00448                 $table = $this->mapping[$table]['mapTableName'];
00449             }
00450         }
00451         // Select API:
00452         $this->lastHandlerKey = $this->handler_getFromTableList($ORIG_tableName);
00453         $hType = (string) $this->handlerCfg[$this->lastHandlerKey]['type'];
00454         switch ($hType) {
00455             case 'native':
00456                 $this->lastQuery = $this->INSERTquery($table, $fields_values, $no_quote_fields);
00457                 if (is_string($this->lastQuery)) {
00458                     $sqlResult = mysql_query($this->lastQuery, $this->handlerInstance[$this->lastHandlerKey]['link']);
00459                 } else {
00460                     $sqlResult = mysql_query($this->lastQuery[0], $this->handlerInstance[$this->lastHandlerKey]['link']);
00461                     $new_id = $this->sql_insert_id();
00462                     $where = $this->cache_autoIncFields[$table] . '=' . $new_id;
00463                     foreach ($this->lastQuery[1] as $field => $content) {
00464                         mysql_query('UPDATE ' . $this->quoteFromTables($table) . ' SET ' . $this->quoteFromTables($field) . '=' . $this->fullQuoteStr($content, $table) . ' WHERE ' . $this->quoteWhereClause($where), $this->handlerInstance[$this->lastHandlerKey]['link']);
00465                     }
00466                 }
00467                 break;
00468             case 'adodb':
00469                 // auto generate ID for auto_increment fields if not present (static import needs this!)
00470                 // should we check the table name here (static_*)?
00471                 if (isset($this->cache_autoIncFields[$table])) {
00472                     if (isset($fields_values[$this->cache_autoIncFields[$table]])) {
00473                         $new_id = $fields_values[$this->cache_autoIncFields[$table]];
00474                         if ($table != 'tx_dbal_debuglog') {
00475                             $this->handlerInstance[$this->lastHandlerKey]->last_insert_id = $new_id;
00476                         }
00477                     } else {
00478                         $new_id = $this->handlerInstance[$this->lastHandlerKey]->GenID($table . '_' . $this->cache_autoIncFields[$table], $this->handlerInstance[$this->lastHandlerKey]->sequenceStart);
00479                         $fields_values[$this->cache_autoIncFields[$table]] = $new_id;
00480                         if ($table != 'tx_dbal_debuglog') {
00481                             $this->handlerInstance[$this->lastHandlerKey]->last_insert_id = $new_id;
00482                         }
00483                     }
00484                 }
00485 
00486                 $this->lastQuery = $this->INSERTquery($table, $fields_values, $no_quote_fields);
00487                 if (is_string($this->lastQuery)) {
00488                     $sqlResult = $this->handlerInstance[$this->lastHandlerKey]->_query($this->lastQuery, FALSE);
00489                 } else {
00490                     $this->handlerInstance[$this->lastHandlerKey]->StartTrans();
00491                     if (strlen($this->lastQuery[0])) {
00492                         $sqlResult = $this->handlerInstance[$this->lastHandlerKey]->_query($this->lastQuery[0], FALSE);
00493                     }
00494                     if (is_array($this->lastQuery[1])) {
00495                         foreach ($this->lastQuery[1] as $field => $content) {
00496                             if (empty($content)) continue;
00497 
00498                             if (isset($this->cache_autoIncFields[$table]) && isset($new_id)) {
00499                                 $this->handlerInstance[$this->lastHandlerKey]->UpdateBlob($this->quoteFromTables($table), $field, $content, $this->quoteWhereClause($this->cache_autoIncFields[$table] . '=' . $new_id));
00500                             } elseif (isset($this->cache_primaryKeys[$table])) {
00501                                 $where = '';
00502                                 $pks = explode(',', $this->cache_primaryKeys[$table]);
00503                                 foreach ($pks as $pk) {
00504                                     if (isset($fields_values[$pk]))
00505                                         $where .= $pk . '=' . $this->fullQuoteStr($fields_values[$pk], $table) . ' AND ';
00506                                 }
00507                                 $where = $this->quoteWhereClause($where . '1=1');
00508                                 $this->handlerInstance[$this->lastHandlerKey]->UpdateBlob($this->quoteFromTables($table), $field, $content, $where);
00509                             } else {
00510                                 $this->handlerInstance[$this->lastHandlerKey]->CompleteTrans(FALSE);
00511                                 die('Could not update BLOB >>>> no WHERE clause found!'); // should never ever happen
00512                             }
00513                         }
00514                     }
00515                     if (is_array($this->lastQuery[2])) {
00516                         foreach ($this->lastQuery[2] as $field => $content) {
00517                             if (empty($content)) continue;
00518 
00519                             if (isset($this->cache_autoIncFields[$table]) && isset($new_id)) {
00520                                 $this->handlerInstance[$this->lastHandlerKey]->UpdateClob($this->quoteFromTables($table), $field, $content, $this->quoteWhereClause($this->cache_autoIncFields[$table] . '=' . $new_id));
00521                             } elseif (isset($this->cache_primaryKeys[$table])) {
00522                                 $where = '';
00523                                 $pks = explode(',', $this->cache_primaryKeys[$table]);
00524                                 foreach ($pks as $pk) {
00525                                     if (isset($fields_values[$pk]))
00526                                         $where .= $pk . '=' . $this->fullQuoteStr($fields_values[$pk], $table) . ' AND ';
00527                                 }
00528                                 $where = $this->quoteWhereClause($where . '1=1');
00529                                 $this->handlerInstance[$this->lastHandlerKey]->UpdateClob($this->quoteFromTables($table), $field, $content, $where);
00530                             } else {
00531                                 $this->handlerInstance[$this->lastHandlerKey]->CompleteTrans(FALSE);
00532                                 die('Could not update CLOB >>>> no WHERE clause found!'); // should never ever happen
00533                             }
00534                         }
00535                     }
00536                     $this->handlerInstance[$this->lastHandlerKey]->CompleteTrans();
00537                 }
00538                 break;
00539             case 'userdefined':
00540                 $sqlResult = $this->handlerInstance[$this->lastHandlerKey]->exec_INSERTquery($table, $fields_values, $no_quote_fields);
00541                 break;
00542         }
00543 
00544         if ($this->printErrors && $this->sql_error()) {
00545             debug(array($this->lastQuery, $this->sql_error()));
00546         }
00547 
00548         if ($this->debug) {
00549             $this->debugHandler(
00550                 'exec_INSERTquery',
00551                     t3lib_div::milliseconds() - $pt,
00552                 array(
00553                     'handlerType' => $hType,
00554                     'args' => array($table, $fields_values),
00555                     'ORIG_tablename' => $ORIG_tableName
00556                 )
00557             );
00558         }
00559         // Return output:
00560         return $sqlResult;
00561     }
00562 
00563     /**
00564      * Creates and executes an INSERT SQL-statement for $table with multiple rows.
00565      * This method uses exec_INSERTquery() and is just a syntax wrapper to it.
00566      *
00567      * @param   string      Table name
00568      * @param   array       Field names
00569      * @param   array       Table rows. Each row should be an array with field values mapping to $fields
00570      * @param   string/array        See fullQuoteArray()
00571      * @return  mixed       Result from last handler, usually TRUE when success and FALSE on failure
00572      */
00573     public function exec_INSERTmultipleRows($table, array $fields, array $rows, $no_quote_fields = FALSE) {
00574         if ((string) $this->handlerCfg[$this->lastHandlerKey]['type'] === 'native') {
00575             return parent::exec_INSERTmultipleRows($table, $fields, $rows, $no_quote_fields);
00576         }
00577 
00578         foreach ($rows as $row) {
00579             $fields_values = array();
00580             foreach ($fields as $key => $value) {
00581                 $fields_values[$value] = $row[$key];
00582             }
00583             $res = $this->exec_INSERTquery($table, $fields_values, $no_quote_fields);
00584         }
00585 
00586         return $res;
00587     }
00588 
00589     /**
00590      * Updates a record from $table
00591      *
00592      * @param   string      Database tablename
00593      * @param   string      WHERE clause, eg. "uid=1". NOTICE: You must escape values in this argument with $this->fullQuoteStr() yourself!
00594      * @param   array       Field values as key=>value pairs. Values will be escaped internally. Typically you would fill an array like "$updateFields" with 'fieldname'=>'value' and pass it to this function as argument.
00595      * @param mixed List/array of keys NOT to quote (eg. SQL functions)
00596      * @return  mixed       Result from handler, usually TRUE when success and FALSE on failure
00597      */
00598     public function exec_UPDATEquery($table, $where, $fields_values, $no_quote_fields = '') {
00599         if ($this->debug) {
00600             $pt = t3lib_div::milliseconds();
00601         }
00602 
00603         // Do table/field mapping:
00604         $ORIG_tableName = $table;
00605         if ($tableArray = $this->map_needMapping($table)) {
00606 
00607             // Field mapping of array:
00608             $fields_values = $this->map_assocArray($fields_values, $tableArray);
00609 
00610             // Where clause table and field mapping:
00611             $whereParts = $this->SQLparser->parseWhereClause($where);
00612             $this->map_sqlParts($whereParts, $tableArray[0]['table']);
00613             $where = $this->SQLparser->compileWhereClause($whereParts, FALSE);
00614 
00615             // Table name:
00616             if ($this->mapping[$table]['mapTableName']) {
00617                 $table = $this->mapping[$table]['mapTableName'];
00618             }
00619         }
00620 
00621         // Select API
00622         $this->lastHandlerKey = $this->handler_getFromTableList($ORIG_tableName);
00623         $hType = (string) $this->handlerCfg[$this->lastHandlerKey]['type'];
00624         switch ($hType) {
00625             case 'native':
00626                 $this->lastQuery = $this->UPDATEquery($table, $where, $fields_values, $no_quote_fields);
00627                 if (is_string($this->lastQuery)) {
00628                     $sqlResult = mysql_query($this->lastQuery, $this->handlerInstance[$this->lastHandlerKey]['link']);
00629                 }
00630                 else {
00631                     $sqlResult = mysql_query($this->lastQuery[0], $this->handlerInstance[$this->lastHandlerKey]['link']);
00632                     foreach ($this->lastQuery[1] as $field => $content) {
00633                         mysql_query('UPDATE ' . $this->quoteFromTables($table) . ' SET ' . $this->quoteFromTables($field) . '=' . $this->fullQuoteStr($content, $table) . ' WHERE ' . $this->quoteWhereClause($where), $this->handlerInstance[$this->lastHandlerKey]['link']);
00634                     }
00635                 }
00636                 break;
00637             case 'adodb':
00638                 $this->lastQuery = $this->UPDATEquery($table, $where, $fields_values, $no_quote_fields);
00639                 if (is_string($this->lastQuery)) {
00640                     $sqlResult = $this->handlerInstance[$this->lastHandlerKey]->_query($this->lastQuery, FALSE);
00641                 } else {
00642                     $this->handlerInstance[$this->lastHandlerKey]->StartTrans();
00643                     if (strlen($this->lastQuery[0])) {
00644                         $sqlResult = $this->handlerInstance[$this->lastHandlerKey]->_query($this->lastQuery[0], FALSE);
00645                     }
00646                     if (is_array($this->lastQuery[1])) {
00647                         foreach ($this->lastQuery[1] as $field => $content) {
00648                             $this->handlerInstance[$this->lastHandlerKey]->UpdateBlob($this->quoteFromTables($table), $field, $content, $this->quoteWhereClause($where));
00649                         }
00650                     }
00651                     if (is_array($this->lastQuery[2])) {
00652                         foreach ($this->lastQuery[2] as $field => $content) {
00653                             $this->handlerInstance[$this->lastHandlerKey]->UpdateClob($this->quoteFromTables($table), $field, $content, $this->quoteWhereClause($where));
00654                         }
00655                     }
00656                     $this->handlerInstance[$this->lastHandlerKey]->CompleteTrans();
00657                 }
00658                 break;
00659             case 'userdefined':
00660                 $sqlResult = $this->handlerInstance[$this->lastHandlerKey]->exec_UPDATEquery($table, $where, $fields_values, $no_quote_fields);
00661                 break;
00662         }
00663 
00664         if ($this->printErrors && $this->sql_error()) {
00665             debug(array($this->lastQuery, $this->sql_error()));
00666         }
00667 
00668         if ($this->debug) {
00669             $this->debugHandler(
00670                 'exec_UPDATEquery',
00671                     t3lib_div::milliseconds() - $pt,
00672                 array(
00673                     'handlerType' => $hType,
00674                     'args' => array($table, $where, $fields_values),
00675                     'ORIG_from_table' => $ORIG_tableName
00676                 )
00677             );
00678         }
00679 
00680         // Return result:
00681         return $sqlResult;
00682     }
00683 
00684     /**
00685      * Deletes records from table
00686      *
00687      * @param   string      Database tablename
00688      * @param   string      WHERE clause, eg. "uid=1". NOTICE: You must escape values in this argument with $this->fullQuoteStr() yourself!
00689      * @return  mixed       Result from handler
00690      */
00691     public function exec_DELETEquery($table, $where) {
00692         if ($this->debug) {
00693             $pt = t3lib_div::milliseconds();
00694         }
00695 
00696         // Do table/field mapping:
00697         $ORIG_tableName = $table;
00698         if ($tableArray = $this->map_needMapping($table)) {
00699 
00700             // Where clause:
00701             $whereParts = $this->SQLparser->parseWhereClause($where);
00702             $this->map_sqlParts($whereParts, $tableArray[0]['table']);
00703             $where = $this->SQLparser->compileWhereClause($whereParts, FALSE);
00704 
00705             // Table name:
00706             if ($this->mapping[$table]['mapTableName']) {
00707                 $table = $this->mapping[$table]['mapTableName'];
00708             }
00709         }
00710 
00711         // Select API
00712         $this->lastHandlerKey = $this->handler_getFromTableList($ORIG_tableName);
00713         $hType = (string) $this->handlerCfg[$this->lastHandlerKey]['type'];
00714         switch ($hType) {
00715             case 'native':
00716                 $this->lastQuery = $this->DELETEquery($table, $where);
00717                 $sqlResult = mysql_query($this->lastQuery, $this->handlerInstance[$this->lastHandlerKey]['link']);
00718                 break;
00719             case 'adodb':
00720                 $this->lastQuery = $this->DELETEquery($table, $where);
00721                 $sqlResult = $this->handlerInstance[$this->lastHandlerKey]->_query($this->lastQuery, FALSE);
00722                 break;
00723             case 'userdefined':
00724                 $sqlResult = $this->handlerInstance[$this->lastHandlerKey]->exec_DELETEquery($table, $where);
00725                 break;
00726         }
00727 
00728         if ($this->printErrors && $this->sql_error()) {
00729             debug(array($this->lastQuery, $this->sql_error()));
00730         }
00731 
00732         if ($this->debug) {
00733             $this->debugHandler(
00734                 'exec_DELETEquery',
00735                     t3lib_div::milliseconds() - $pt,
00736                 array(
00737                     'handlerType' => $hType,
00738                     'args' => array($table, $where),
00739                     'ORIG_from_table' => $ORIG_tableName
00740                 )
00741             );
00742         }
00743 
00744         // Return result:
00745         return $sqlResult;
00746     }
00747 
00748     /**
00749      * Selects records from Data Source
00750      *
00751      * @param   string $select_fields List of fields to select from the table. This is what comes right after "SELECT ...". Required value.
00752      * @param   string $from_table Table(s) from which to select. This is what comes right after "FROM ...". Required value.
00753      * @param   string $where_clause Optional additional WHERE clauses put in the end of the query. NOTICE: You must escape values in this argument with $this->fullQquoteStr() yourself! DO NOT PUT IN GROUP BY, ORDER BY or LIMIT!
00754      * @param   string $groupBy Optional GROUP BY field(s), if none, supply blank string.
00755      * @param   string $orderBy Optional ORDER BY field(s), if none, supply blank string.
00756      * @param   string $limit Optional LIMIT value ([begin,]max), if none, supply blank string.
00757      * @return  mixed       Result from handler. Typically object from DBAL layers.
00758      */
00759     public function exec_SELECTquery($select_fields, $from_table, $where_clause, $groupBy = '', $orderBy = '', $limit = '') {
00760         if ($this->debug) {
00761             $pt = t3lib_div::milliseconds();
00762         }
00763 
00764         // Map table / field names if needed:
00765         $ORIG_tableName = $from_table; // Saving table names in $ORIG_from_table since $from_table is transformed beneath:
00766         $parsedFromTable = array();
00767         $remappedParameters = array();
00768         if ($tableArray = $this->map_needMapping($ORIG_tableName, FALSE, $parsedFromTable)) {
00769             $from = $parsedFromTable ? $parsedFromTable : $from_table;
00770             $remappedParameters = $this->map_remapSELECTQueryParts($select_fields, $from, $where_clause, $groupBy, $orderBy);
00771         }
00772 
00773         // Get handler key and select API:
00774         $this->lastHandlerKey = $this->handler_getFromTableList($ORIG_tableName);
00775         $hType = (string) $this->handlerCfg[$this->lastHandlerKey]['type'];
00776         switch ($hType) {
00777             case 'native':
00778                 if (count($remappedParameters) > 0) {
00779                     list($select_fields, $from_table, $where_clause, $groupBy, $orderBy) = $this->compileSelectParameters($remappedParameters);
00780                 }
00781                 $this->lastQuery = $this->SELECTquery($select_fields, $from_table, $where_clause, $groupBy, $orderBy, $limit);
00782                 $sqlResult = mysql_query($this->lastQuery, $this->handlerInstance[$this->lastHandlerKey]['link']);
00783                 $this->resourceIdToTableNameMap[(string) $sqlResult] = $ORIG_tableName;
00784                 break;
00785             case 'adodb':
00786                 if ($limit != '') {
00787                     $splitLimit = t3lib_div::intExplode(',', $limit); // Splitting the limit values:
00788                     if ($splitLimit[1]) { // If there are two parameters, do mapping differently than otherwise:
00789                         $numrows = $splitLimit[1];
00790                         $offset = $splitLimit[0];
00791                     } else {
00792                         $numrows = $splitLimit[0];
00793                         $offset = 0;
00794                     }
00795 
00796                     if (count($remappedParameters) > 0) {
00797                         $sqlResult = $this->handlerInstance[$this->lastHandlerKey]->SelectLimit($this->SELECTqueryFromArray($remappedParameters), $numrows, $offset);
00798                     } else {
00799                         $sqlResult = $this->handlerInstance[$this->lastHandlerKey]->SelectLimit($this->SELECTquery($select_fields, $from_table, $where_clause, $groupBy, $orderBy), $numrows, $offset);
00800                     }
00801                     $this->lastQuery = $sqlResult->sql;
00802                 } else {
00803                     if (count($remappedParameters) > 0) {
00804                         $this->lastQuery = $this->SELECTqueryFromArray($remappedParameters);
00805                     } else {
00806                         $this->lastQuery = $this->SELECTquery($select_fields, $from_table, $where_clause, $groupBy, $orderBy);
00807                     }
00808                     $sqlResult = $this->handlerInstance[$this->lastHandlerKey]->_Execute($this->lastQuery);
00809                 }
00810 
00811                 $sqlResult->TYPO3_DBAL_handlerType = 'adodb'; // Setting handler type in result object (for later recognition!)
00812                 $sqlResult->TYPO3_DBAL_tableList = $ORIG_tableName;
00813                 break;
00814             case 'userdefined':
00815                 if (count($remappedParameters) > 0) {
00816                     list($select_fields, $from_table, $where_clause, $groupBy, $orderBy) = $this->compileSelectParameters($remappedParameters);
00817                 }
00818                 $sqlResult = $this->handlerInstance[$this->lastHandlerKey]->exec_SELECTquery($select_fields, $from_table, $where_clause, $groupBy, $orderBy, $limit);
00819                 if (is_object($sqlResult)) {
00820                     $sqlResult->TYPO3_DBAL_handlerType = 'userdefined'; // Setting handler type in result object (for later recognition!)
00821                     $sqlResult->TYPO3_DBAL_tableList = $ORIG_tableName;
00822                 }
00823                 break;
00824         }
00825 
00826         if ($this->printErrors && $this->sql_error()) {
00827             debug(array($this->lastQuery, $this->sql_error()));
00828         }
00829 
00830         if ($this->debug) {
00831             $data = array(
00832                 'handlerType' => $hType,
00833                 'args' => array($from_table, $select_fields, $where_clause, $groupBy, $orderBy, $limit),
00834                 'ORIG_from_table' => $ORIG_tableName,
00835             );
00836             if ($this->conf['debugOptions']['numberRows']) {
00837                 $data['numberRows'] = $this->sql_num_rows($sqlResult);
00838             }
00839             $this->debugHandler(
00840                 'exec_SELECTquery',
00841                     t3lib_div::milliseconds() - $pt,
00842                 $data
00843             );
00844         }
00845 
00846         // Return result handler.
00847         return $sqlResult;
00848     }
00849 
00850     /**
00851      * Truncates a table.
00852      *
00853      * @param   string      Database tablename
00854      * @return  mixed       Result from handler
00855      */
00856     public function exec_TRUNCATEquery($table) {
00857         if ($this->debug) {
00858             $pt = t3lib_div::milliseconds();
00859         }
00860 
00861         // Do table/field mapping:
00862         $ORIG_tableName = $table;
00863         if ($tableArray = $this->map_needMapping($table)) {
00864             // Table name:
00865             if ($this->mapping[$table]['mapTableName']) {
00866                 $table = $this->mapping[$table]['mapTableName'];
00867             }
00868         }
00869 
00870         // Select API
00871         $this->lastHandlerKey = $this->handler_getFromTableList($ORIG_tableName);
00872         $hType = (string) $this->handlerCfg[$this->lastHandlerKey]['type'];
00873         switch ($hType) {
00874             case 'native':
00875                 $this->lastQuery = $this->TRUNCATEquery($table);
00876                 $sqlResult = mysql_query($this->lastQuery, $this->handlerInstance[$this->lastHandlerKey]['link']);
00877                 break;
00878             case 'adodb':
00879                 $this->lastQuery = $this->TRUNCATEquery($table);
00880                 $sqlResult = $this->handlerInstance[$this->lastHandlerKey]->_query($this->lastQuery, FALSE);
00881                 break;
00882             case 'userdefined':
00883                 $sqlResult = $this->handlerInstance[$this->lastHandlerKey]->exec_TRUNCATEquery($table);
00884                 break;
00885         }
00886 
00887         if ($this->printErrors && $this->sql_error()) {
00888             debug(array($this->lastQuery, $this->sql_error()));
00889         }
00890 
00891         if ($this->debug) {
00892             $this->debugHandler(
00893                 'exec_TRUNCATEquery',
00894                     t3lib_div::milliseconds() - $pt,
00895                 array(
00896                     'handlerType' => $hType,
00897                     'args' => array($table),
00898                     'ORIG_from_table' => $ORIG_tableName
00899                 )
00900             );
00901         }
00902 
00903         // Return result:
00904         return $sqlResult;
00905     }
00906 
00907     /**
00908      * Executes a query.
00909      * EXPERIMENTAL since TYPO3 4.4.
00910      *
00911      * @param array $queryParts SQL parsed by method parseSQL() of t3lib_sqlparser
00912      * @return pointer Result pointer / DBAL object
00913      * @see ux_t3lib_db::sql_query()
00914      */
00915     protected function exec_query(array $queryParts) {
00916         switch ($queryParts['type']) {
00917             case 'SELECT':
00918                 $selectFields = $this->SQLparser->compileFieldList($queryParts['SELECT']);
00919                 $fromTables = $this->SQLparser->compileFromTables($queryParts['FROM']);
00920                 $whereClause = isset($queryParts['WHERE']) ? $this->SQLparser->compileWhereClause($queryParts['WHERE']) : '1=1';
00921                 $groupBy = isset($queryParts['GROUPBY']) ? $this->SQLparser->compileFieldList($queryParts['GROUPBY']) : '';
00922                 $orderBy = isset($queryParts['ORDERBY']) ? $this->SQLparser->compileFieldList($queryParts['ORDERBY']) : '';
00923                 $limit = isset($queryParts['LIMIT']) ? $this->SQLparser->compileWhereClause($queryParts['LIMIT']) : '';
00924                 return $this->exec_SELECTquery($selectFields, $fromTables, $whereClause, $groupBy, $orderBy, $limit);
00925 
00926             case 'UPDATE':
00927                 $table = $queryParts['TABLE'];
00928                 $fields = array();
00929                 foreach ($queryParts['FIELDS'] as $fN => $fV) {
00930                     $fields[$fN] = $fV[0];
00931                 }
00932                 $whereClause = isset($queryParts['WHERE']) ? $this->SQLparser->compileWhereClause($queryParts['WHERE']) : '1=1';
00933                 return $this->exec_UPDATEquery($table, $whereClause, $fields);
00934 
00935             case 'INSERT':
00936                 $table = $queryParts['TABLE'];
00937                 $values = array();
00938                 if (isset($queryParts['VALUES_ONLY']) && is_array($queryParts['VALUES_ONLY'])) {
00939                     $fields = $GLOBALS['TYPO3_DB']->cache_fieldType[$table];
00940                     $fc = 0;
00941                     foreach ($fields as $fn => $fd) {
00942                         $values[$fn] = $queryParts['VALUES_ONLY'][$fc++][0];
00943                     }
00944                 } else {
00945                     foreach ($queryParts['FIELDS'] as $fN => $fV) {
00946                         $values[$fN] = $fV[0];
00947                     }
00948                 }
00949                 return $this->exec_INSERTquery($table, $values);
00950 
00951             case 'DELETE':
00952                 $table = $queryParts['TABLE'];
00953                 $whereClause = isset($queryParts['WHERE']) ? $this->SQLparser->compileWhereClause($queryParts['WHERE']) : '1=1';
00954                 return $this->exec_DELETEquery($table, $whereClause);
00955 
00956             case 'TRUNCATETABLE':
00957                 $table = $queryParts['TABLE'];
00958                 return $this->exec_TRUNCATEquery($table);
00959         }
00960     }
00961 
00962 
00963     /**************************************
00964      *
00965      * Query building
00966      *
00967      **************************************/
00968 
00969     /**
00970      * Creates an INSERT SQL-statement for $table from the array with field/value pairs $fields_values.
00971      * Usage count/core: 4
00972      *
00973      * @param   string      See exec_INSERTquery()
00974      * @param   array       See exec_INSERTquery()
00975      * @param mixed     See exec_INSERTquery()
00976      * @return  mixed       Full SQL query for INSERT as string or array (unless $fields_values does not contain any elements in which case it will be FALSE). If BLOB fields will be affected and one is not running the native type, an array will be returned, where 0 => plain SQL, 1 => fieldname/value pairs of BLOB fields
00977      */
00978     public function INSERTquery($table, $fields_values, $no_quote_fields = '') {
00979         // Table and fieldnames should be "SQL-injection-safe" when supplied to this function (contrary to values in the arrays which may be insecure).
00980         if (is_array($fields_values) && count($fields_values)) {
00981 
00982             if (is_string($no_quote_fields)) {
00983                 $no_quote_fields = explode(',', $no_quote_fields);
00984             } elseif (!is_array($no_quote_fields)) {
00985                 $no_quote_fields = array();
00986             }
00987 
00988             $blobfields = array();
00989             $nArr = array();
00990             foreach ($fields_values as $k => $v) {
00991                 if (!$this->runningNative() && $this->sql_field_metatype($table, $k) == 'B') {
00992                     // we skip the field in the regular INSERT statement, it is only in blobfields
00993                     $blobfields[$this->quoteFieldNames($k)] = $v;
00994                 } elseif (!$this->runningNative() && $this->sql_field_metatype($table, $k) == 'XL') {
00995                     // we skip the field in the regular INSERT statement, it is only in clobfields
00996                     $clobfields[$this->quoteFieldNames($k)] = $v;
00997                 } else {
00998                     // Add slashes old-school:
00999                     // cast numerical values
01000                     $mt = $this->sql_field_metatype($table, $k);
01001                     if ($mt{0} == 'I') {
01002                         $v = (int) $v;
01003                     } else if ($mt{0} == 'F') {
01004                         $v = (double) $v;
01005                     }
01006 
01007                     $nArr[$this->quoteFieldNames($k)] = (!in_array($k, $no_quote_fields)) ? $this->fullQuoteStr($v, $table) : $v;
01008                 }
01009             }
01010 
01011             if (count($blobfields) || count($clobfields)) {
01012                 if (count($nArr)) {
01013                     $query[0] = 'INSERT INTO ' . $this->quoteFromTables($table) . '
01014                     (
01015                         ' . implode(',
01016                         ', array_keys($nArr)) . '
01017                     ) VALUES (
01018                         ' . implode(',
01019                         ', $nArr) . '
01020                     )';
01021                 }
01022                 if (count($blobfields)) $query[1] = $blobfields;
01023                 if (count($clobfields)) $query[2] = $clobfields;
01024                 if ($this->debugOutput || $this->store_lastBuiltQuery) $this->debug_lastBuiltQuery = $query[0];
01025             } else {
01026                 $query = 'INSERT INTO ' . $this->quoteFromTables($table) . '
01027                 (
01028                     ' . implode(',
01029                     ', array_keys($nArr)) . '
01030                 ) VALUES (
01031                     ' . implode(',
01032                     ', $nArr) . '
01033                 )';
01034 
01035                 if ($this->debugOutput || $this->store_lastBuiltQuery) $this->debug_lastBuiltQuery = $query;
01036             }
01037 
01038             return $query;
01039         }
01040     }
01041 
01042     /**
01043      * Creates an INSERT SQL-statement for $table with multiple rows.
01044      * This method will create multiple INSERT queries concatenated with ';'
01045      *
01046      * @param   string      Table name
01047      * @param   array       Field names
01048      * @param   array       Table rows. Each row should be an array with field values mapping to $fields
01049      * @param   string/array        See fullQuoteArray()
01050      * @return  array       Full SQL query for INSERT as array of strings (unless $fields_values does not contain any elements in which case it will be FALSE). If BLOB fields will be affected and one is not running the native type, an array will be returned for each row, where 0 => plain SQL, 1 => fieldname/value pairs of BLOB fields.
01051      */
01052     public function INSERTmultipleRows($table, array $fields, array $rows, $no_quote_fields = FALSE) {
01053         if ((string) $this->handlerCfg[$this->lastHandlerKey]['type'] === 'native') {
01054             return parent::INSERTmultipleRows($table, $fields, $rows, $no_quote_fields);
01055         }
01056 
01057         $result = array();
01058 
01059         foreach ($rows as $row) {
01060             $fields_values = array();
01061             foreach ($fields as $key => $value) {
01062                 $fields_values[$value] = $row[$key];
01063             }
01064             $rowQuery = $this->INSERTquery($table, $fields_values, $no_quote_fields);
01065             if (is_array($rowQuery)) {
01066                 $result[] = $rowQuery;
01067             } else {
01068                 $result[][0] = $rowQuery;
01069             }
01070         }
01071 
01072         return $result;
01073     }
01074 
01075     /**
01076      * Creates an UPDATE SQL-statement for $table where $where-clause (typ. 'uid=...') from the array with field/value pairs $fields_values.
01077      * Usage count/core: 6
01078      *
01079      * @param   string      See exec_UPDATEquery()
01080      * @param   string      See exec_UPDATEquery()
01081      * @param   array       See exec_UPDATEquery()
01082      * @param   mixed       See exec_UPDATEquery()
01083      * @return  mixed       Full SQL query for UPDATE as string or array (unless $fields_values does not contain any elements in which case it will be FALSE). If BLOB fields will be affected and one is not running the native type, an array will be returned, where 0 => plain SQL, 1 => fieldname/value pairs of BLOB fields
01084      */
01085     public function UPDATEquery($table, $where, $fields_values, $no_quote_fields = '') {
01086         // Table and fieldnames should be "SQL-injection-safe" when supplied to this function (contrary to values in the arrays which may be insecure).
01087         if (is_string($where)) {
01088             $fields = array();
01089             $blobfields = array();
01090             $clobfields = array();
01091             if (is_array($fields_values) && count($fields_values)) {
01092 
01093                 if (is_string($no_quote_fields)) {
01094                     $no_quote_fields = explode(',', $no_quote_fields);
01095                 } elseif (!is_array($no_quote_fields)) {
01096                     $no_quote_fields = array();
01097                 }
01098 
01099                 $nArr = array();
01100                 foreach ($fields_values as $k => $v) {
01101                     if (!$this->runningNative() && $this->sql_field_metatype($table, $k) == 'B') {
01102                         // we skip the field in the regular UPDATE statement, it is only in blobfields
01103                         $blobfields[$this->quoteFieldNames($k)] = $v;
01104                     } elseif (!$this->runningNative() && $this->sql_field_metatype($table, $k) == 'XL') {
01105                         // we skip the field in the regular UPDATE statement, it is only in clobfields
01106                         $clobfields[$this->quoteFieldNames($k)] = $v;
01107                     } else {
01108                         // Add slashes old-school:
01109                         // cast numeric values
01110                         $mt = $this->sql_field_metatype($table, $k);
01111                         if ($mt{0} == 'I') {
01112                             $v = (int) $v;
01113                         } else if ($mt{0} == 'F') {
01114                             $v = (double) $v;
01115                         }
01116                         $nArr[] = $this->quoteFieldNames($k) . '=' . ((!in_array($k, $no_quote_fields)) ? $this->fullQuoteStr($v, $table) : $v);
01117                     }
01118                 }
01119             }
01120 
01121             if (count($blobfields) || count($clobfields)) {
01122                 if (count($nArr)) {
01123                     $query[0] = 'UPDATE ' . $this->quoteFromTables($table) . '
01124                         SET
01125                             ' . implode(',
01126                             ', $nArr) .
01127                             (strlen($where) > 0 ? '
01128                         WHERE
01129                             ' . $this->quoteWhereClause($where) : '');
01130                 }
01131                 if (count($blobfields)) {
01132                     $query[1] = $blobfields;
01133                 }
01134                 if (count($clobfields)) {
01135                     $query[2] = $clobfields;
01136                 }
01137                 if ($this->debugOutput || $this->store_lastBuiltQuery) {
01138                     $this->debug_lastBuiltQuery = $query[0];
01139                 }
01140             } else {
01141                 $query = 'UPDATE ' . $this->quoteFromTables($table) . '
01142                     SET
01143                         ' . implode(',
01144                         ', $nArr) .
01145                         (strlen($where) > 0 ? '
01146                     WHERE
01147                         ' . $this->quoteWhereClause($where) : '');
01148 
01149                 if ($this->debugOutput || $this->store_lastBuiltQuery) {
01150                     $this->debug_lastBuiltQuery = $query;
01151                 }
01152             }
01153             return $query;
01154         } else {
01155             throw new InvalidArgumentException(
01156                 'TYPO3 Fatal Error: "Where" clause argument for UPDATE query was not a string in $this->UPDATEquery() !',
01157                 1270853880
01158             );
01159         }
01160     }
01161 
01162     /**
01163      * Creates a DELETE SQL-statement for $table where $where-clause
01164      * Usage count/core: 3
01165      *
01166      * @param   string      See exec_DELETEquery()
01167      * @param   string      See exec_DELETEquery()
01168      * @return  string      Full SQL query for DELETE
01169      */
01170     public function DELETEquery($table, $where) {
01171         if (is_string($where)) {
01172             $table = $this->quoteFromTables($table);
01173             $where = $this->quoteWhereClause($where);
01174 
01175             $query = parent::DELETEquery($table, $where);
01176 
01177             if ($this->debugOutput || $this->store_lastBuiltQuery) $this->debug_lastBuiltQuery = $query;
01178             return $query;
01179         } else {
01180             die('<strong>TYPO3 Fatal Error:</strong> "Where" clause argument for DELETE query was not a string in $this->DELETEquery() !');
01181         }
01182     }
01183 
01184     /**
01185      * Creates a SELECT SQL-statement
01186      * Usage count/core: 11
01187      *
01188      * @param   string      See exec_SELECTquery()
01189      * @param   string      See exec_SELECTquery()
01190      * @param   string      See exec_SELECTquery()
01191      * @param   string      See exec_SELECTquery()
01192      * @param   string      See exec_SELECTquery()
01193      * @param   string      See exec_SELECTquery()
01194      * @return  string      Full SQL query for SELECT
01195      */
01196     public function SELECTquery($select_fields, $from_table, $where_clause, $groupBy = '', $orderBy = '', $limit = '') {
01197         $this->lastHandlerKey = $this->handler_getFromTableList($from_table);
01198         $hType = (string) $this->handlerCfg[$this->lastHandlerKey]['type'];
01199         if ($hType === 'adodb' && $this->runningADOdbDriver('postgres')) {
01200             // Possibly rewrite the LIMIT to be PostgreSQL-compatible
01201             $splitLimit = t3lib_div::intExplode(',', $limit); // Splitting the limit values:
01202             if ($splitLimit[1]) { // If there are two parameters, do mapping differently than otherwise:
01203                 $numrows = $splitLimit[1];
01204                 $offset = $splitLimit[0];
01205                 $limit = $numrows . ' OFFSET ' . $offset;
01206             }
01207         }
01208 
01209         $select_fields = $this->quoteFieldNames($select_fields);
01210         $from_table = $this->quoteFromTables($from_table);
01211         $where_clause = $this->quoteWhereClause($where_clause);
01212         $groupBy = $this->quoteGroupBy($groupBy);
01213         $orderBy = $this->quoteOrderBy($orderBy);
01214 
01215         // Call parent method to build actual query
01216         $query = parent::SELECTquery($select_fields, $from_table, $where_clause, $groupBy, $orderBy, $limit);
01217 
01218         if ($this->debugOutput || $this->store_lastBuiltQuery) {
01219             $this->debug_lastBuiltQuery = $query;
01220         }
01221 
01222         return $query;
01223     }
01224 
01225     /**
01226      * Creates a SELECT SQL-statement to be used with an ADOdb backend.
01227      *
01228      * @param   array       parsed parameters: array($select_fields, $from_table, $where_clause, $groupBy, $orderBy)
01229      * @return  string      Full SQL query for SELECT
01230      */
01231     protected function SELECTqueryFromArray(array $params) {
01232         // $select_fields
01233         $params[0] = $this->_quoteFieldNames($params[0]);
01234         // $from_table
01235         $params[1] = $this->_quoteFromTables($params[1]);
01236         // $where_clause
01237         if (count($params[2]) > 0) {
01238             $params[2] = $this->_quoteWhereClause($params[2]);
01239         }
01240         // $group_by
01241         if (count($params[3]) > 0) {
01242             $params[3] = $this->_quoteGroupBy($params[3]);
01243         }
01244         // $order_by
01245         if (count($params[4]) > 0) {
01246             $params[4] = $this->_quoteOrderBy($params[4]);
01247         }
01248 
01249         // Compile the SELECT parameters
01250         list($select_fields, $from_table, $where_clause, $groupBy, $orderBy) = $this->compileSelectParameters($params);
01251 
01252         // Call parent method to build actual query
01253         $query = parent::SELECTquery($select_fields, $from_table, $where_clause, $groupBy, $orderBy);
01254 
01255         if ($this->debugOutput || $this->store_lastBuiltQuery) {
01256             $this->debug_lastBuiltQuery = $query;
01257         }
01258 
01259         return $query;
01260     }
01261 
01262     /**
01263      * Compiles and returns an array of SELECTquery parameters (without $limit) to
01264      * be used with SELECTquery() or exec_SELECTquery().
01265      *
01266      * @param array $params
01267      * @return array array($select_fields, $from_table, $where_clause, $groupBy, $orderBy)
01268      */
01269     protected function compileSelectParameters(array $params) {
01270         $select_fields = $this->SQLparser->compileFieldList($params[0]);
01271         $from_table = $this->SQLparser->compileFromTables($params[1]);
01272         $where_clause = (count($params[2]) > 0) ? $this->SQLparser->compileWhereClause($params[2]) : '';
01273         $groupBy = (count($params[3]) > 0) ? $this->SQLparser->compileFieldList($params[3]) : '';
01274         $orderBy = (count($params[4]) > 0) ? $this->SQLparser->compileFieldList($params[4]) : '';
01275 
01276         return array($select_fields, $from_table, $where_clause, $groupBy, $orderBy);
01277     }
01278 
01279     /**
01280      * Creates a TRUNCATE TABLE SQL-statement
01281      *
01282      * @param   string      See exec_TRUNCATEquery()
01283      * @return  string      Full SQL query for TRUNCATE TABLE
01284      */
01285     public function TRUNCATEquery($table) {
01286         $table = $this->quoteFromTables($table);
01287 
01288         // Call parent method to build actual query
01289         $query = parent::TRUNCATEquery($table);
01290 
01291         if ($this->debugOutput || $this->store_lastBuiltQuery) {
01292             $this->debug_lastBuiltQuery = $query;
01293         }
01294 
01295         return $query;
01296     }
01297 
01298     /**************************************
01299      *
01300      * Prepared Query Support
01301      *
01302      **************************************/
01303 
01304     /**
01305      * Creates a SELECT prepared SQL statement.
01306      *
01307      * @param string See exec_SELECTquery()
01308      * @param string See exec_SELECTquery()
01309      * @param string See exec_SELECTquery()
01310      * @param string See exec_SELECTquery()
01311      * @param string See exec_SELECTquery()
01312      * @param string See exec_SELECTquery()
01313      * @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 t3lib_db_PreparedStatement::PARAM_AUTOTYPE.
01314      * @return t3lib_db_PreparedStatement Prepared statement
01315      */
01316     public function prepare_SELECTquery($select_fields, $from_table, $where_clause, $groupBy = '', $orderBy = '', $limit = '', array $input_parameters = array()) {
01317         if ($this->debug) {
01318             $pt = t3lib_div::milliseconds();
01319         }
01320 
01321         $precompiledParts = array();
01322 
01323         if ($this->queryCache) {
01324             $cacheKey = 'prepare_SELECTquery-' . tx_dbal_querycache::getCacheKey(array(
01325                 'selectFields' => $select_fields,
01326                 'fromTable' => $from_table,
01327                 'whereClause' => $where_clause,
01328                 'groupBy' => $groupBy,
01329                 'orderBy' => $orderBy,
01330                 'limit' => $limit,
01331             ));
01332             if ($this->queryCache->has($cacheKey)) {
01333                 $precompiledParts = $this->queryCache->get($cacheKey);
01334                 if ($this->debug) {
01335                     $data = array(
01336                         'args' => array($from_table, $select_fields, $where_clause, $groupBy, $orderBy, $limit, $input_parameters),
01337                         'precompiledParts' => $precompiledParts,
01338                     );
01339                     $this->debugHandler(
01340                         'prepare_SELECTquery (cache hit)',
01341                             t3lib_div::milliseconds() - $pt,
01342                         $data
01343                     );
01344                 }
01345             }
01346         }
01347 
01348         if (count($precompiledParts) == 0) {
01349             // Map table / field names if needed:
01350             $ORIG_tableName = $from_table; // Saving table names in $ORIG_from_table since $from_table is transformed beneath:
01351             $parsedFromTable = array();
01352             $queryComponents = array();
01353             if ($tableArray = $this->map_needMapping($ORIG_tableName, FALSE, $parsedFromTable)) {
01354                 $from = $parsedFromTable ? $parsedFromTable : $from_table;
01355                 $components = $this->map_remapSELECTQueryParts($select_fields, $from, $where_clause, $groupBy, $orderBy);
01356                 $queryComponents['SELECT'] = $components[0];
01357                 $queryComponents['FROM'] = $components[1];
01358                 $queryComponents['WHERE'] = $components[2];
01359                 $queryComponents['GROUPBY'] = $components[3];
01360                 $queryComponents['ORDERBY'] = $components[4];
01361                 $queryComponents['parameters'] = $components[5];
01362             } else {
01363                 $queryComponents = $this->getQueryComponents($select_fields, $from_table, $where_clause, $groupBy, $orderBy, $limit);
01364             }
01365 
01366             $queryComponents['ORIG_tableName'] = $ORIG_tableName;
01367 
01368             if (!$this->runningNative()) {
01369                 // Quotes all fields
01370                 $queryComponents['SELECT'] = $this->_quoteFieldNames($queryComponents['SELECT']);
01371                 $queryComponents['FROM'] = $this->_quoteFromTables($queryComponents['FROM']);
01372                 $queryComponents['WHERE'] = $this->_quoteWhereClause($queryComponents['WHERE']);
01373                 $queryComponents['GROUPBY'] = $this->_quoteGroupBy($queryComponents['GROUPBY']);
01374                 $queryComponents['ORDERBY'] = $this->_quoteOrderBy($queryComponents['ORDERBY']);
01375             }
01376 
01377             $precompiledParts = $this->precompileSELECTquery($queryComponents);
01378             if ($this->queryCache) {
01379                 try {
01380                     $this->queryCache->set($cacheKey, $precompiledParts);
01381                 } catch (t3lib_cache_Exception $e) {
01382                     if ($this->debug) {
01383                         t3lib_div::devLog($e->getMessage(), 'dbal', 1);
01384                     }
01385                 }
01386             }
01387         }
01388 
01389         $preparedStatement = t3lib_div::makeInstance('t3lib_db_PreparedStatement', '', $from_table, $precompiledParts);
01390         /* @var $preparedStatement t3lib_db_PreparedStatement */
01391 
01392         // Bind values to parameters
01393         foreach ($input_parameters as $key => $value) {
01394             $preparedStatement->bindValue($key, $value, t3lib_db_PreparedStatement::PARAM_AUTOTYPE);
01395         }
01396 
01397         if ($this->debug) {
01398             $data = array(
01399                 'args' => array($from_table, $select_fields, $where_clause, $groupBy, $orderBy, $limit, $input_parameters),
01400                 'ORIG_from_table' => $ORIG_tableName,
01401             );
01402             $this->debugHandler(
01403                 'prepare_SELECTquery',
01404                     t3lib_div::milliseconds() - $pt,
01405                 $data
01406             );
01407         }
01408 
01409         // Return prepared statement
01410         return $preparedStatement;
01411     }
01412 
01413     /**
01414      * Returns the parsed query components.
01415      *
01416      * @param string $select_fields
01417      * @param string $from_table
01418      * @param string $where_clause
01419      * @param string $groupBy
01420      * @param string $orderBy
01421      * @param string $limit
01422      * @return array
01423      */
01424     protected function getQueryComponents($select_fields, $from_table, $where_clause, $groupBy, $orderBy, $limit) {
01425         $queryComponents = array(
01426             'SELECT' => '',
01427             'FROM' => '',
01428             'WHERE' => '',
01429             'GROUPBY' => '',
01430             'ORDERBY' => '',
01431             'LIMIT' => '',
01432             'parameters' => array(),
01433         );
01434 
01435         $this->lastHandlerKey = $this->handler_getFromTableList($from_table);
01436         $hType = (string) $this->handlerCfg[$this->lastHandlerKey]['type'];
01437         if ($hType === 'adodb' && $this->runningADOdbDriver('postgres')) {
01438             // Possibly rewrite the LIMIT to be PostgreSQL-compatible
01439             $splitLimit = t3lib_div::intExplode(',', $limit); // Splitting the limit values:
01440             if ($splitLimit[1]) { // If there are two parameters, do mapping differently than otherwise:
01441                 $numrows = $splitLimit[1];
01442                 $offset = $splitLimit[0];
01443                 $limit = $numrows . ' OFFSET ' . $offset;
01444             }
01445         }
01446         $queryComponents['LIMIT'] = $limit;
01447 
01448         $queryComponents['SELECT'] = $this->SQLparser->parseFieldList($select_fields);
01449         if ($this->SQLparser->parse_error) {
01450             die($this->SQLparser->parse_error . ' in ' . __FILE__ . ' : ' . __LINE__);
01451         }
01452 
01453         $queryComponents['FROM'] = $this->SQLparser->parseFromTables($from_table);
01454 
01455         $queryComponents['WHERE'] = $this->SQLparser->parseWhereClause($where_clause, '', $queryComponents['parameters']);
01456         if (!is_array($queryComponents['WHERE'])) {
01457             die('Could not parse where clause in ' . __FILE__ . ' : ' . __LINE__);
01458         }
01459 
01460         $queryComponents['GROUPBY'] = $this->SQLparser->parseFieldList($groupBy);
01461         $queryComponents['ORDERBY'] = $this->SQLparser->parseFieldList($orderBy);
01462 
01463         // Return the query components
01464         return $queryComponents;
01465     }
01466 
01467     /**
01468      * Precompiles a SELECT prepared SQL statement.
01469      *
01470      * @param array $components
01471      * @return array Precompiled SQL statement
01472      */
01473     protected function precompileSELECTquery(array $components) {
01474         $parameterWrap = '__' . dechex(time()) . '__';
01475         foreach ($components['parameters'] as $key => $params) {
01476             if ($key === '?') {
01477                 foreach ($params as $index => $param) {
01478                     $components['parameters'][$key][$index][0] = $parameterWrap . $param[0] . $parameterWrap;
01479                 }
01480             } else {
01481                 $components['parameters'][$key][0] = $parameterWrap . $params[0] . $parameterWrap;
01482             }
01483         }
01484 
01485         $select_fields = $this->SQLparser->compileFieldList($components['SELECT']);
01486         $from_table = $this->SQLparser->compileFromTables($components['FROM']);
01487         $where_clause = $this->SQLparser->compileWhereClause($components['WHERE']);
01488         $groupBy = $this->SQLparser->compileFieldList($components['GROUPBY']);
01489         $orderBy = $this->SQLparser->compileFieldList($components['ORDERBY']);
01490         $limit = $components['LIMIT'];
01491         $precompiledParts = array();
01492 
01493         $this->lastHandlerKey = $this->handler_getFromTableList($components['ORIG_tableName']);
01494         $hType = (string) $this->handlerCfg[$this->lastHandlerKey]['type'];
01495         $precompiledParts['handler'] = $hType;
01496         $precompiledParts['ORIG_tableName'] = $components['ORIG_tableName'];
01497 
01498         switch ($hType) {
01499             case 'native':
01500                 $query = parent::SELECTquery($select_fields, $from_table, $where_clause, $groupBy, $orderBy, $limit);
01501                 $precompiledParts['queryParts'] = explode($parameterWrap, $query);
01502                 break;
01503             case 'adodb':
01504                 $query = parent::SELECTquery($select_fields, $from_table, $where_clause, $groupBy, $orderBy);
01505                 $precompiledParts['queryParts'] = explode($parameterWrap, $query);
01506                 $precompiledParts['LIMIT'] = $limit;
01507                 break;
01508             case 'userdefined':
01509                 $precompiledParts['queryParts'] = array(
01510                     'SELECT' => $select_fields,
01511                     'FROM' => $from_table,
01512                     'WHERE' => $where_clause,
01513                     'GROUPBY' => $groupBy,
01514                     'ORDERBY' => $orderBy,
01515                     'LIMIT' => $limit,
01516                 );
01517                 break;
01518         }
01519 
01520         return $precompiledParts;
01521     }
01522 
01523     /**
01524      * Executes a prepared query.
01525      *
01526      * @param string $query The query to execute
01527      * @param array $queryComponents The components of the query to execute
01528      * @return pointer MySQL result pointer / DBAL object
01529      * @access protected This method may only be called by t3lib_db_PreparedStatement
01530      */
01531     public function exec_PREPAREDquery($query, array $precompiledParts) {
01532         if ($this->debug) {
01533             $pt = t3lib_div::milliseconds();
01534         }
01535 
01536         // Get handler key and select API:
01537         switch ($precompiledParts['handler']) {
01538             case 'native':
01539                 $this->lastQuery = $query;
01540                 $sqlResult = mysql_query($this->lastQuery, $this->handlerInstance[$this->lastHandlerKey]['link']);
01541                 $this->resourceIdToTableNameMap[(string) $sqlResult] = $precompiledParts['ORIG_tableName'];
01542                 break;
01543             case 'adodb':
01544                 $limit = $precompiledParts['LIMIT'];
01545                 if ($this->runningADOdbDriver('postgres')) {
01546                     // Possibly rewrite the LIMIT to be PostgreSQL-compatible
01547                     $splitLimit = t3lib_div::intExplode(',', $limit); // Splitting the limit values:
01548                     if ($splitLimit[1]) { // If there are two parameters, do mapping differently than otherwise:
01549                         $numrows = $splitLimit[1];
01550                         $offset = $splitLimit[0];
01551                         $limit = $numrows . ' OFFSET ' . $offset;
01552                     }
01553                 }
01554                 if ($limit != '') {
01555                     $splitLimit = t3lib_div::intExplode(',', $limit); // Splitting the limit values:
01556                     if ($splitLimit[1]) { // If there are two parameters, do mapping differently than otherwise:
01557                         $numrows = $splitLimit[1];
01558                         $offset = $splitLimit[0];
01559                     } else {
01560                         $numrows = $splitLimit[0];
01561                         $offset = 0;
01562                     }
01563 
01564                     $sqlResult = $this->handlerInstance[$this->lastHandlerKey]->SelectLimit($query, $numrows, $offset);
01565                     $this->lastQuery = $sqlResult->sql;
01566                 } else {
01567                     $this->lastQuery = $query;
01568                     $sqlResult = $this->handlerInstance[$this->lastHandlerKey]->_Execute($this->lastQuery);
01569                 }
01570 
01571                 $sqlResult->TYPO3_DBAL_handlerType = 'adodb'; // Setting handler type in result object (for later recognition!)
01572                 $sqlResult->TYPO3_DBAL_tableList = $precompiledParts['ORIG_tableName'];
01573                 break;
01574             case 'userdefined':
01575                 $queryParts = $precompiledParts['queryParts'];
01576                 $sqlResult = $this->handlerInstance[$this->lastHandlerKey]->exec_SELECTquery(
01577                     $queryParts['SELECT'],
01578                     $queryParts['FROM'],
01579                     $queryParts['WHERE'],
01580                     $queryParts['GROUPBY'],
01581                     $queryParts['ORDERBY'],
01582                     $queryParts['LIMIT']
01583                 );
01584                 if (is_object($sqlResult)) {
01585                     $sqlResult->TYPO3_DBAL_handlerType = 'userdefined'; // Setting handler type in result object (for later recognition!)
01586                     $sqlResult->TYPO3_DBAL_tableList = $precompiledParts['ORIG_tableName'];
01587                 }
01588                 break;
01589         }
01590 
01591         if ($this->printErrors && $this->sql_error()) {
01592             debug(array($this->lastQuery, $this->sql_error()));
01593         }
01594 
01595         if ($this->debug) {
01596             $data = array(
01597                 'handlerType' => $precompiledParts['handler'],
01598                 'args' => $precompiledParts,
01599                 'ORIG_from_table' => $precompiledParts['ORIG_tableName'],
01600             );
01601             if ($this->conf['debugOptions']['numberRows']) {
01602                 $data['numberRows'] = $this->sql_num_rows($sqlResult);
01603             }
01604             $this->debugHandler(
01605                 'exec_PREPAREDquery',
01606                     t3lib_div::milliseconds() - $pt,
01607                 $data
01608             );
01609         }
01610 
01611         // Return result handler.
01612         return $sqlResult;
01613     }
01614 
01615     /**************************************
01616      *
01617      * Functions for quoting table/field names
01618      *
01619      **************************************/
01620 
01621     /**
01622      * Quotes components of a SELECT subquery.
01623      *
01624      * @param array $components Array of SQL query components
01625      * @return array
01626      */
01627     protected function quoteSELECTsubquery(array $components) {
01628         $components['SELECT'] = $this->_quoteFieldNames($components['SELECT']);
01629         $components['FROM'] = $this->_quoteFromTables($components['FROM']);
01630         $components['WHERE'] = $this->_quoteWhereClause($components['WHERE']);
01631         return $components;
01632     }
01633 
01634     /**
01635      * Quotes field (and table) names with the quote character suitable for the DB being used
01636      * Use quoteFieldNames instead!
01637      *
01638      * @param   string      List of fields to be selected from DB
01639      * @return  string      Quoted list of fields to be selected from DB
01640      * @deprecated since TYPO3 4.0, will be removed in TYPO3 4.6
01641      */
01642     public function quoteSelectFields($select_fields) {
01643         t3lib_div::logDeprecatedFunction();
01644 
01645         $this->quoteFieldNames($select_fields);
01646     }
01647 
01648     /**
01649      * Quotes field (and table) names with the quote character suitable for the DB being used
01650      *
01651      * @param   string      List of fields to be used in query to DB
01652      * @return  string      Quoted list of fields to be in query to DB
01653      */
01654     public function quoteFieldNames($select_fields) {
01655         if ($select_fields == '') {
01656             return '';
01657         }
01658         if ($this->runningNative()) {
01659             return $select_fields;
01660         }
01661 
01662         $select_fields = $this->SQLparser->parseFieldList($select_fields);
01663         if ($this->SQLparser->parse_error) {
01664             die($this->SQLparser->parse_error . ' in ' . __FILE__ . ' : ' . __LINE__);
01665         }
01666         $select_fields = $this->_quoteFieldNames($select_fields);
01667 
01668         return $this->SQLparser->compileFieldList($select_fields);
01669     }
01670 
01671     /**
01672      * Quotes field (and table) names in a SQL SELECT clause acccording to DB rules
01673      *
01674      * @param array $select_fields The parsed fields to quote
01675      * @return array
01676      * @see quoteFieldNames()
01677      */
01678     protected function _quoteFieldNames(array $select_fields) {
01679         foreach ($select_fields as $k => $v) {
01680             if ($select_fields[$k]['field'] != '' && $select_fields[$k]['field'] != '*' && !is_numeric($select_fields[$k]['field'])) {
01681                 $select_fields[$k]['field'] = $this->quoteName($select_fields[$k]['field']);
01682             }
01683             if ($select_fields[$k]['table'] != '' && !is_numeric($select_fields[$k]['table'])) {
01684                 $select_fields[$k]['table'] = $this->quoteName($select_fields[$k]['table']);
01685             }
01686             if ($select_fields[$k]['as'] != '') {
01687                 $select_fields[$k]['as'] = $this->quoteName($select_fields[$k]['as']);
01688             }
01689             if (isset($select_fields[$k]['func_content.']) && $select_fields[$k]['func_content.'][0]['func_content'] != '*') {
01690                 $select_fields[$k]['func_content.'][0]['func_content'] = $this->quoteFieldNames($select_fields[$k]['func_content.'][0]['func_content']);
01691                 $select_fields[$k]['func_content'] = $this->quoteFieldNames($select_fields[$k]['func_content']);
01692             }
01693             if (isset($select_fields[$k]['flow-control'])) {
01694                 // Quoting flow-control statements
01695                 if ($select_fields[$k]['flow-control']['type'] === 'CASE') {
01696                     if (isset($select_fields[$k]['flow-control']['case_field'])) {
01697                         $select_fields[$k]['flow-control']['case_field'] = $this->quoteFieldNames($select_fields[$k]['flow-control']['case_field']);
01698                     }
01699                     foreach ($select_fields[$k]['flow-control']['when'] as $key => $when) {
01700                         $select_fields[$k]['flow-control']['when'][$key]['when_value'] = $this->_quoteWhereClause($when['when_value']);
01701                     }
01702                 }
01703             }
01704         }
01705 
01706         return $select_fields;
01707     }
01708 
01709     /**
01710      * Quotes table names with the quote character suitable for the DB being used
01711      *
01712      * @param   string      List of tables to be selected from DB
01713      * @return  string      Quoted list of tables to be selected from DB
01714      */
01715     public function quoteFromTables($from_table) {
01716         if ($from_table == '') {
01717             return '';
01718         }
01719         if ($this->runningNative()) {
01720             return $from_table;
01721         }
01722 
01723         $from_table = $this->SQLparser->parseFromTables($from_table);
01724         $from_table = $this->_quoteFromTables($from_table);
01725         return $this->SQLparser->compileFromTables($from_table);
01726     }
01727 
01728     /**
01729      * Quotes table names in a SQL FROM clause acccording to DB rules
01730      *
01731      * @param array $from_table The parsed FROM clause to quote
01732      * @return array
01733      * @see quoteFromTables()
01734      */
01735     protected function _quoteFromTables(array $from_table) {
01736         foreach ($from_table as $k => $v) {
01737             $from_table[$k]['table'] = $this->quoteName($from_table[$k]['table']);
01738             if ($from_table[$k]['as'] != '') {
01739                 $from_table[$k]['as'] = $this->quoteName($from_table[$k]['as']);
01740             }
01741             if (is_array($v['JOIN'])) {
01742                 foreach ($v['JOIN'] as $joinCnt => $join) {
01743                     $from_table[$k]['JOIN'][$joinCnt]['withTable'] = $this->quoteName($join['withTable']);
01744                     $from_table[$k]['JOIN'][$joinCnt]['as'] = ($join['as']) ? $this->quoteName($join['as']) : '';
01745                     foreach ($from_table[$k]['JOIN'][$joinCnt]['ON'] as &$condition) {
01746                         $condition['left']['table'] = ($condition['left']['table']) ? $this->quoteName($condition['left']['table']) : '';
01747                         $condition['left']['field'] = $this->quoteName($condition['left']['field']);
01748                         $condition['right']['table'] = ($condition['right']['table']) ? $this->quoteName($condition['right']['table']) : '';
01749                         $condition['right']['field'] = $this->quoteName($condition['right']['field']);
01750                     }
01751                 }
01752             }
01753         }
01754 
01755         return $from_table;
01756     }
01757 
01758     /**
01759      * Quotes the field (and table) names within a where clause with the quote character suitable for the DB being used
01760      *
01761      * @param   string      A where clause that can be parsed by parseWhereClause
01762      * @return  string      Usable where clause with quoted field/table names
01763      */
01764     public function quoteWhereClause($where_clause) {
01765         if ($where_clause === '' || $this->runningNative()) {
01766             return $where_clause;
01767         }
01768 
01769         $where_clause = $this->SQLparser->parseWhereClause($where_clause);
01770         if (is_array($where_clause)) {
01771             $where_clause = $this->_quoteWhereClause($where_clause);
01772             $where_clause = $this->SQLparser->compileWhereClause($where_clause);
01773         } else {
01774             die('Could not parse where clause in ' . __FILE__ . ' : ' . __LINE__);
01775         }
01776 
01777         return $where_clause;
01778     }
01779 
01780     /**
01781      * Quotes field names in a SQL WHERE clause acccording to DB rules
01782      *
01783      * @param   array       $where_clause The parsed WHERE clause to quote
01784      * @return  array
01785      * @see quoteWhereClause()
01786      */
01787     protected function _quoteWhereClause(array $where_clause) {
01788         foreach ($where_clause as $k => $v) {
01789             // Look for sublevel:
01790             if (is_array($where_clause[$k]['sub'])) {
01791                 $where_clause[$k]['sub'] = $this->_quoteWhereClause($where_clause[$k]['sub']);
01792             } elseif (isset($v['func'])) {
01793                 switch ($where_clause[$k]['func']['type']) {
01794                     case 'EXISTS':
01795                         $where_clause[$k]['func']['subquery'] = $this->quoteSELECTsubquery($v['func']['subquery']);
01796                         break;
01797                     case 'FIND_IN_SET':
01798                         // quoteStr that will be used for Oracle
01799                         $pattern = str_replace($where_clause[$k]['func']['str'][1], '\\' . $where_clause[$k]['func']['str'][1], $where_clause[$k]['func']['str'][0]);
01800                         // table is not really needed and may in fact be empty in real statements
01801                         // but it's not overriden from t3lib_db at the moment...
01802                         $patternForLike = $this->escapeStrForLike($pattern, $where_clause[$k]['func']['table']);
01803                         $where_clause[$k]['func']['str_like'] = $patternForLike;
01804 
01805                     // BEWARE: no break here to have next statements too
01806                     case 'IFNULL':
01807                     case 'LOCATE':
01808                         if ($where_clause[$k]['func']['table'] != '') {
01809                             $where_clause[$k]['func']['table'] = $this->quoteName($v['func']['table']);
01810                         }
01811                         if ($where_clause[$k]['func']['field'] != '') {
01812                             $where_clause[$k]['func']['field'] = $this->quoteName($v['func']['field']);
01813                         }
01814                         break;
01815                 }
01816             } else {
01817                 if ($where_clause[$k]['table'] != '') {
01818                     $where_clause[$k]['table'] = $this->quoteName($where_clause[$k]['table']);
01819                 }
01820                 if (!is_numeric($where_clause[$k]['field'])) {
01821                     $where_clause[$k]['field'] = $this->quoteName($where_clause[$k]['field']);
01822                 }
01823                 if (isset($where_clause[$k]['calc_table'])) {
01824                     if ($where_clause[$k]['calc_table'] != '') {
01825                         $where_clause[$k]['calc_table'] = $this->quoteName($where_clause[$k]['calc_table']);
01826                     }
01827                     if ($where_clause[$k]['calc_field'] != '') {
01828                         $where_clause[$k]['calc_field'] = $this->quoteName($where_clause[$k]['calc_field']);
01829                     }
01830                 }
01831             }
01832             if ($where_clause[$k]['comparator']) {
01833                 if (isset($v['value']['operator'])) {
01834                     foreach ($where_clause[$k]['value']['args'] as $argK => $fieldDef) {
01835                         $where_clause[$k]['value']['args'][$argK]['table'] = $this->quoteName($fieldDef['table']);
01836                         $where_clause[$k]['value']['args'][$argK]['field'] = $this->quoteName($fieldDef['field']);
01837                     }
01838                 } else {
01839                     // Detecting value type; list or plain:
01840                     if (t3lib_div::inList('NOTIN,IN', strtoupper(str_replace(array(' ', "\n", "\r", "\t"), '', $where_clause[$k]['comparator'])))) {
01841                         if (isset($v['subquery'])) {
01842                             $where_clause[$k]['subquery'] = $this->quoteSELECTsubquery($v['subquery']);
01843                         }
01844                     } else {
01845                         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], '.')) {
01846                             $where_clause[$k]['value'][0] = $this->quoteFieldNames($where_clause[$k]['value'][0]);
01847                         }
01848                     }
01849                 }
01850             }
01851         }
01852 
01853         return $where_clause;
01854     }
01855 
01856     /**
01857      * Quotes the field (and table) names within a group by clause with the quote
01858      * character suitable for the DB being used
01859      *
01860      * @param   string      A group by clause that can by parsed by parseFieldList
01861      * @return  string      Usable group by clause with quoted field/table names
01862      */
01863     protected function quoteGroupBy($groupBy) {
01864         if ($groupBy === '') {
01865             return '';
01866         }
01867         if ($this->runningNative()) {
01868             return $groupBy;
01869         }
01870 
01871         $groupBy = $this->SQLparser->parseFieldList($groupBy);
01872         $groupBy = $this->_quoteGroupBy($groupBy);
01873 
01874         return $this->SQLparser->compileFieldList($groupBy);
01875     }
01876 
01877     /**
01878      * Quotes field names in a SQL GROUP BY clause acccording to DB rules
01879      *
01880      * @param   array       $groupBy The parsed GROUP BY clause to quote
01881      * @return  array
01882      * @see quoteGroupBy()
01883      */
01884     protected function _quoteGroupBy(array $groupBy) {
01885         foreach ($groupBy as $k => $v) {
01886             $groupBy[$k]['field'] = $this->quoteName($groupBy[$k]['field']);
01887             if ($groupBy[$k]['table'] != '') {
01888                 $groupBy[$k]['table'] = $this->quoteName($groupBy[$k]['table']);
01889             }
01890         }
01891         return $groupBy;
01892     }
01893 
01894     /**
01895      * Quotes the field (and table) names within an order by clause with the quote
01896      * character suitable for the DB being used
01897      *
01898      * @param   string      An order by clause that can by parsed by parseFieldList
01899      * @return  string      Usable order by clause with quoted field/table names
01900      */
01901     protected function quoteOrderBy($orderBy) {
01902         if ($orderBy === '') {
01903             return '';
01904         }
01905         if ($this->runningNative()) {
01906             return $orderBy;
01907         }
01908 
01909         $orderBy = $this->SQLparser->parseFieldList($orderBy);
01910         $orderBy = $this->_quoteOrderBy($orderBy);
01911 
01912         return $this->SQLparser->compileFieldList($orderBy);
01913     }
01914 
01915     /**
01916      * Quotes field names in a SQL ORDER BY clause acccording to DB rules
01917      *
01918      * @param   array       $orderBy The parsed ORDER BY clause to quote
01919      * @return  array
01920      * @see quoteOrderBy()
01921      */
01922     protected function _quoteOrderBy(array $orderBy) {
01923         foreach ($orderBy as $k => $v) {
01924             $orderBy[$k]['field'] = $this->quoteName($orderBy[$k]['field']);
01925             if ($orderBy[$k]['table'] != '') {
01926                 $orderBy[$k]['table'] = $this->quoteName($orderBy[$k]['table']);
01927             }
01928         }
01929         return $orderBy;
01930     }
01931 
01932 
01933     /**************************************
01934      *
01935      * Various helper functions
01936      *
01937      **************************************/
01938 
01939     /**
01940      * Escaping and quoting values for SQL statements.
01941      *
01942      * @param   string      Input string
01943      * @param   string      Table name for which to quote string. Just enter the table that the field-value is selected from (and any DBAL will look up which handler to use and then how to quote the string!).
01944      * @return  string      Output string; Wrapped in single quotes and quotes in the string (" / ') and \ will be backslashed (or otherwise based on DBAL handler)
01945      * @see quoteStr()
01946      */
01947     public function fullQuoteStr($str, $table) {
01948         return '\'' . $this->quoteStr($str, $table) . '\'';
01949     }
01950 
01951     /**
01952      * Substitution for PHP function "addslashes()"
01953      * 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()!
01954      *
01955      * @param   string      Input string
01956      * @param   string      Table name for which to quote string. Just enter the table that the field-value is selected from (and any DBAL will look up which handler to use and then how to quote the string!).
01957      * @return  string      Output string; Quotes (" / ') and \ will be backslashed (or otherwise based on DBAL handler)
01958      * @see quoteStr()
01959      */
01960     public function quoteStr($str, $table) {
01961         $this->lastHandlerKey = $this->handler_getFromTableList($table);
01962         switch ((string) $this->handlerCfg[$this->lastHandlerKey]['type']) {
01963             case 'native':
01964                 if ($this->handlerInstance[$this->lastHandlerKey]['link']) {
01965                     $str = mysql_real_escape_string($str, $this->handlerInstance[$this->lastHandlerKey]['link']);
01966                 } else {
01967                     // link may be null when unit testing DBAL
01968                     $str = str_replace('\'', '\\\'', $str);
01969                 }
01970                 break;
01971             case 'adodb':
01972                 $str = substr($this->handlerInstance[$this->lastHandlerKey]->qstr($str), 1, -1);
01973                 break;
01974             case 'userdefined':
01975                 $str = $this->handlerInstance[$this->lastHandlerKey]->quoteStr($str);
01976                 break;
01977             default:
01978                 die('No handler found!!!');
01979                 break;
01980         }
01981 
01982         return $str;
01983     }
01984 
01985     /**
01986      * Quotes an object name (table name, field, ...)
01987      *
01988      * @param   string      Object's name
01989      * @param   string      Handler key
01990      * @param   boolean     If method NameQuote() is not used, whether to use backticks instead of driver-specific quotes
01991      * @return  string      Properly-quoted object's name
01992      */
01993     public function quoteName($name, $handlerKey = NULL, $useBackticks = FALSE) {
01994         $handlerKey = $handlerKey ? $handlerKey : $this->lastHandlerKey;
01995         $useNameQuote = isset($this->handlerCfg[$handlerKey]['config']['useNameQuote']) ? $this->handlerCfg[$handlerKey]['config']['useNameQuote'] : FALSE;
01996         if ($useNameQuote) {
01997             return $this->handlerInstance[$handlerKey]->DataDictionary->NameQuote($name);
01998         } else {
01999             $quote = $useBackticks ? '`' : $this->handlerInstance[$handlerKey]->nameQuote;
02000             return $quote . $name . $quote;
02001         }
02002     }
02003 
02004     /**
02005      * Return MetaType for native field type (ADOdb only!)
02006      *
02007      * @param   string      native type as reported by admin_get_fields()
02008      * @param   string      Table name for which query type string. Important for detection of DBMS handler of the query!
02009      * @return  string      Meta type (currenly ADOdb syntax only, http://phplens.com/lens/adodb/docs-adodb.htm#metatype)
02010      */
02011     public function MetaType($type, $table, $max_length = -1) {
02012         $this->lastHandlerKey = $this->handler_getFromTableList($table);
02013         $str = '';
02014         switch ((string) $this->handlerCfg[$this->lastHandlerKey]['type']) {
02015             case 'native':
02016                 $str = $type;
02017                 break;
02018             case 'adodb':
02019                 if (in_array($table, $this->cache_fieldType)) {
02020                     $rs = $this->handlerInstance[$this->lastHandlerKey]->SelectLimit('SELECT * FROM ' . $this->quoteFromTables($table), 1);
02021                     $str = $rs->MetaType($type, $max_length);
02022                 }
02023                 break;
02024             case 'userdefined':
02025                 $str = $this->handlerInstance[$this->lastHandlerKey]->MetaType($str, $table, $max_length);
02026                 break;
02027             default:
02028                 die('No handler found!!!');
02029                 break;
02030         }
02031 
02032         return $str;
02033     }
02034 
02035 
02036     /**
02037      * Return MetaType for native MySQL field type
02038      *
02039      * @param   string      native type as reported as in mysqldump files
02040      * @return  string      Meta type (currenly ADOdb syntax only, http://phplens.com/lens/adodb/docs-adodb.htm#metatype)
02041      */
02042     public function MySQLMetaType($t) {
02043 
02044         switch (strtoupper($t)) {
02045             case 'STRING':
02046             case 'CHAR':
02047             case 'VARCHAR':
02048             case 'TINYBLOB':
02049             case 'TINYTEXT':
02050             case 'ENUM':
02051             case 'SET':
02052                 return 'C';
02053 
02054             case 'TEXT':
02055             case 'LONGTEXT':
02056             case 'MEDIUMTEXT':
02057                 return 'XL';
02058 
02059             case 'IMAGE':
02060             case 'LONGBLOB':
02061             case 'BLOB':
02062             case 'MEDIUMBLOB':
02063                 return 'B';
02064 
02065             case 'YEAR':
02066             case 'DATE':
02067                 return 'D';
02068 
02069             case 'TIME':
02070             case 'DATETIME':
02071             case 'TIMESTAMP':
02072                 return 'T';
02073 
02074             case 'FLOAT':
02075             case 'DOUBLE':
02076                 return 'F';
02077 
02078             case 'INT':
02079             case 'INTEGER':
02080             case 'TINYINT':
02081             case 'SMALLINT':
02082             case 'MEDIUMINT':
02083             case 'BIGINT':
02084                 return 'I8'; // we always return I8 to be on the safe side. Under some circumstances the fields are to small otherwise...
02085 
02086             default:
02087                 return 'N';
02088         }
02089     }
02090 
02091     /**
02092      * Return actual MySQL type for meta field type
02093      *
02094      * @param   string      Meta type (currenly ADOdb syntax only, http://phplens.com/lens/adodb/docs-adodb.htm#metatype)
02095      * @return  string      native type as reported as in mysqldump files, uppercase
02096      */
02097     public function MySQLActualType($meta) {
02098         switch (strtoupper($meta)) {
02099             case 'C':
02100                 return 'VARCHAR';
02101             case 'XL':
02102             case 'X':
02103                 return 'LONGTEXT';
02104 
02105             case 'C2':
02106                 return 'VARCHAR';
02107             case 'X2':
02108                 return 'LONGTEXT';
02109 
02110             case 'B':
02111                 return 'LONGBLOB';
02112 
02113             case 'D':
02114                 return 'DATE';
02115             case 'T':
02116                 return 'DATETIME';
02117             case 'L':
02118                 return 'TINYINT';
02119 
02120             case 'I':
02121             case 'I1':
02122             case 'I2':
02123             case 'I4':
02124             case 'I8':
02125                 return 'BIGINT'; // we only have I8 in DBAL, see MySQLMetaType()
02126 
02127             case 'F':
02128                 return 'DOUBLE';
02129             case 'N':
02130                 return 'NUMERIC';
02131 
02132             default:
02133                 return $meta;
02134         }
02135     }
02136 
02137 
02138     /**************************************
02139      *
02140      * SQL wrapper functions (Overriding parent methods)
02141      * (For use in your applications)
02142      *
02143      **************************************/
02144 
02145     /**
02146      * Returns the error status on the most recent sql() execution (based on $this->lastHandlerKey)
02147      *
02148      * @return  string      Handler error strings
02149      */
02150     public function sql_error() {
02151         switch ($this->handlerCfg[$this->lastHandlerKey]['type']) {
02152             case 'native':
02153                 $output = mysql_error($this->handlerInstance[$this->lastHandlerKey]['link']);
02154                 break;
02155             case 'adodb':
02156                 $output = $this->handlerInstance[$this->lastHandlerKey]->ErrorMsg();
02157                 break;
02158             case 'userdefined':
02159                 $output = $this->handlerInstance[$this->lastHandlerKey]->sql_error();
02160                 break;
02161         }
02162         return $output;
02163     }
02164 
02165     /**
02166      * Returns the error number on the most recent sql() execution (based on $this->lastHandlerKey)
02167      *
02168      * @return  int     Handler error number
02169      */
02170     public function sql_errno() {
02171         switch ($this->handlerCfg[$this->lastHandlerKey]['type']) {
02172             case 'native':
02173                 $output = mysql_errno($this->handlerInstance[$this->lastHandlerKey]['link']);
02174                 break;
02175             case 'adodb':
02176                 $output = $this->handlerInstance[$this->lastHandlerKey]->ErrorNo();
02177                 break;
02178             case 'userdefined':
02179                 $output = $this->handlerInstance[$this->lastHandlerKey]->sql_errno();
02180                 break;
02181         }
02182         return $output;
02183     }
02184 
02185     /**
02186      * Returns the number of selected rows.
02187      *
02188      * @param   pointer     Result pointer / DBAL object
02189      * @return  integer     Number of resulting rows.
02190      */
02191     public function sql_num_rows(&$res) {
02192         if ($res === FALSE) {
02193             return 0;
02194         }
02195 
02196         $handlerType = is_object($res) ? $res->TYPO3_DBAL_handlerType : 'native';
02197         switch ($handlerType) {
02198             case 'native':
02199                 $output = mysql_num_rows($res);
02200                 break;
02201             case 'adodb':
02202                 $output = method_exists($res, 'RecordCount') ? $res->RecordCount() : 0;
02203                 break;
02204             case 'userdefined':
02205                 $output = $res->sql_num_rows();
02206                 break;
02207         }
02208         return $output;
02209     }
02210 
02211     /**
02212      * Returns an associative array that corresponds to the fetched row, or FALSE if there are no more rows.
02213      *
02214      * @param   pointer     MySQL result pointer (of SELECT query) / DBAL object
02215      * @return  array       Associative array of result row.
02216      */
02217     public function sql_fetch_assoc(&$res) {
02218         $output = array();
02219 
02220         $handlerType = is_object($res) ? $res->TYPO3_DBAL_handlerType : (is_resource($res) ? 'native' : FALSE);
02221         switch ($handlerType) {
02222             case 'native':
02223                 $output = mysql_fetch_assoc($res);
02224                 $tableList = $this->resourceIdToTableNameMap[(string) $res]; // Reading list of tables from SELECT query:
02225                 break;
02226             case 'adodb':
02227                 // Check if method exists for the current $res object.
02228                 // If a table exists in TCA but not in the db, a error
02229                 // occured because $res is not a valid object.
02230                 if (method_exists($res, 'FetchRow')) {
02231                     $output = $res->FetchRow();
02232                     $tableList = $res->TYPO3_DBAL_tableList; // Reading list of tables from SELECT query:
02233 
02234                     // Removing all numeric/integer keys.
02235                     // A workaround because in ADOdb we would need to know what we want before executing the query...
02236                     // MSSQL does not support ADODB_FETCH_BOTH and always returns an assoc. array instead. So
02237                     // we don't need to remove anything.
02238                     if (is_array($output)) {
02239                         if ($this->runningADOdbDriver('mssql')) {
02240                             // MSSQL does not know such thing as an empty string. So it returns one space instead, which we must fix.
02241                             foreach ($output as $key => $value) {
02242                                 if ($value === ' ') {
02243                                     $output[$key] = '';
02244                                 }
02245                             }
02246                         } else {
02247                             foreach ($output as $key => $value) {
02248                                 if (is_integer($key)) {
02249                                     unset($output[$key]);
02250                                 }
02251                             }
02252                         }
02253                     }
02254                 }
02255                 break;
02256             case 'userdefined':
02257                 $output = $res->sql_fetch_assoc();
02258                 $tableList = $res->TYPO3_DBAL_tableList; // Reading list of tables from SELECT query:
02259                 break;
02260         }
02261 
02262         // Table/Fieldname mapping:
02263         if (is_array($output)) {
02264             if ($tables = $this->map_needMapping($tableList, TRUE)) {
02265                 $output = $this->map_assocArray($output, $tables, 1);
02266             }
02267         }
02268 
02269         // Return result:
02270         return $output;
02271     }
02272 
02273     /**
02274      * Returns an array that corresponds to the fetched row, or FALSE if there are no more rows.
02275      * The array contains the values in numerical indices.
02276      *
02277      * @param   pointer     MySQL result pointer (of SELECT query) / DBAL object
02278      * @return  array       Array with result rows.
02279      */
02280     public function sql_fetch_row(&$res) {
02281         $handlerType = is_object($res) ? $res->TYPO3_DBAL_handlerType : 'native';
02282         switch ($handlerType) {
02283             case 'native':
02284                 $output = mysql_fetch_row($res);
02285                 break;
02286             case 'adodb':
02287                 // Check if method exists for the current $res object.
02288                 // If a table exists in TCA but not in the db, a error
02289                 // occured because $res is not a valid object.
02290                 if (method_exists($res, 'FetchRow')) {
02291                     $output = $res->FetchRow();
02292 
02293                     // Removing all assoc. keys.
02294                     // A workaround because in ADOdb we would need to know what we want before executing the query...
02295                     // MSSQL does not support ADODB_FETCH_BOTH and always returns an assoc. array instead. So
02296                     // we need to convert resultset.
02297                     if (is_array($output)) {
02298                         $keyIndex = 0;
02299                         foreach ($output as $key => $value) {
02300                             unset($output[$key]);
02301                             if (is_integer($key) || $this->runningADOdbDriver('mssql')) {
02302                                 $output[$keyIndex] = $value;
02303                                 if ($value === ' ') {
02304                                     // MSSQL does not know such thing as an empty string. So it returns one space instead, which we must fix.
02305                                     $output[$keyIndex] = '';
02306                                 }
02307                                 $keyIndex++;
02308                             }
02309                         }
02310                     }
02311                 }
02312                 break;
02313             case 'userdefined':
02314                 $output = $res->sql_fetch_row();
02315                 break;
02316         }
02317         return $output;
02318     }
02319 
02320     /**
02321      * Free result memory / unset result object
02322      *
02323      * @param   pointer     MySQL result pointer to free / DBAL object
02324      * @return  boolean     Returns TRUE on success or FALSE on failure.
02325      */
02326     public function sql_free_result(&$res) {
02327         if ($res === FALSE) {
02328             return FALSE;
02329         }
02330 
02331         $handlerType = is_object($res) ? $res->TYPO3_DBAL_handlerType : 'native';
02332         switch ($handlerType) {
02333             case 'native':
02334                 $output = mysql_free_result($res);
02335                 break;
02336             case 'adodb':
02337                 if (method_exists($res, 'Close')) {
02338                     $res->Close();
02339                     unset($res);
02340                     $output = TRUE;
02341                 } else {
02342                     $output = FALSE;
02343                 }
02344                 break;
02345             case 'userdefined':
02346                 unset($res);
02347                 break;
02348         }
02349         return $output;
02350     }
02351 
02352     /**
02353      * Get the ID generated from the previous INSERT operation
02354      *
02355      * @return  integer     The uid of the last inserted record.
02356      */
02357     public function sql_insert_id() {
02358         switch ($this->handlerCfg[$this->lastHandlerKey]['type']) {
02359             case 'native':
02360                 $output = mysql_insert_id($this->handlerInstance[$this->lastHandlerKey]['link']);
02361                 break;
02362             case 'adodb':
02363                 $output = $this->handlerInstance[$this->lastHandlerKey]->last_insert_id;
02364                 break;
02365             case 'userdefined':
02366                 $output = $this->handlerInstance[$this->lastHandlerKey]->sql_insert_id();
02367                 break;
02368         }
02369         return $output;
02370     }
02371 
02372     /**
02373      * Returns the number of rows affected by the last INSERT, UPDATE or DELETE query
02374      *
02375      * @return  integer     Number of rows affected by last query
02376      */
02377     public function sql_affected_rows() {
02378         switch ($this->handlerCfg[$this->lastHandlerKey]['type']) {
02379             case 'native':
02380                 $output = mysql_affected_rows();
02381                 break;
02382             case 'adodb':
02383                 $output = $this->handlerInstance[$this->lastHandlerKey]->Affected_Rows();
02384                 break;
02385             case 'userdefined':
02386                 $output = $this->handlerInstance[$this->lastHandlerKey]->sql_affected_rows();
02387                 break;
02388         }
02389         return $output;
02390     }
02391 
02392     /**
02393      * Move internal result pointer
02394      *
02395      * @param   pointer     MySQL result pointer (of SELECT query) / DBAL object
02396      * @param   integer     Seek result number.
02397      * @return  boolean     Returns TRUE on success or FALSE on failure.
02398      */
02399     public function sql_data_seek(&$res, $seek) {
02400         $handlerType = is_object($res) ? $res->TYPO3_DBAL_handlerType : 'native';
02401         switch ($handlerType) {
02402             case 'native':
02403                 $output = mysql_data_seek($res, $seek);
02404                 break;
02405             case 'adodb':
02406                 $output = $res->Move($seek);
02407                 break;
02408             case 'userdefined':
02409                 $output = $res->sql_data_seek($seek);
02410                 break;
02411         }
02412         return $output;
02413     }
02414 
02415     /**
02416      * Get the type of the specified field in a result
02417      *
02418      * If the first parameter is a string, it is used as table name for the lookup.
02419      *
02420      * @param   pointer     MySQL result pointer (of SELECT query) / DBAL object / table name
02421      * @param   integer     Field index. In case of ADOdb a string (field name!) FIXME
02422      * @return  string      Returns the type of the specified field index
02423      */
02424     public function sql_field_metatype($table, $field) {
02425         // If $table and/or $field are mapped, use the original names instead
02426         foreach ($this->mapping as $tableName => $tableMapInfo) {
02427             if (isset($tableMapInfo['mapTableName']) && $tableMapInfo['mapTableName'] === $table) {
02428                 // Table name is mapped => use original name
02429                 $table = $tableName;
02430             }
02431 
02432             if (isset($tableMapInfo['mapFieldNames'])) {
02433                 foreach ($tableMapInfo['mapFieldNames'] as $fieldName => $fieldMapInfo) {
02434                     if ($fieldMapInfo === $field) {
02435                         // Field name is mapped => use original name
02436                         $field = $fieldName;
02437                     }
02438                 }
02439             }
02440         }
02441 
02442         return $this->cache_fieldType[$table][$field]['metaType'];
02443     }
02444 
02445     /**
02446      * Get the type of the specified field in a result
02447      *
02448      * If the first parameter is a string, it is used as table name for the lookup.
02449      *
02450      * @param   pointer     MySQL result pointer (of SELECT query) / DBAL object / table name
02451      * @param   integer     Field index. In case of ADOdb a string (field name!) FIXME
02452      * @return  string      Returns the type of the specified field index
02453      */
02454     public function sql_field_type(&$res, $pointer) {
02455         if ($res === null) {
02456             debug(array('no res in sql_field_type!'));
02457             return 'text';
02458         }
02459         elseif (is_string($res)) {
02460             if ($res === 'tx_dbal_debuglog') return 'text';
02461             $handlerType = 'adodb';
02462         }
02463         else {
02464             $handlerType = is_object($res) ? $res->TYPO3_DBAL_handlerType : 'native';
02465         }
02466 
02467         switch ($handlerType) {
02468             case 'native':
02469                 $output = mysql_field_type($res, $pointer);
02470                 break;
02471             case 'adodb':
02472                 if (is_string($pointer)) {
02473                     $output = $this->cache_fieldType[$res][$pointer]['type'];
02474                 }
02475 
02476                 break;
02477             case 'userdefined':
02478                 $output = $res->sql_field_type($pointer);
02479                 break;
02480         }
02481 
02482         return $output;
02483     }
02484 
02485 
02486     /**********
02487      *
02488      * Legacy functions, bound to _DEFAULT handler. (Overriding parent methods)
02489      * Deprecated or still experimental.
02490      *
02491      **********/
02492 
02493     /**
02494      * Executes query (on DEFAULT handler!)
02495      * DEPRECATED - use exec_* functions from this class instead!
02496      *
02497      * @param   string      Database name
02498      * @param   string      Query to execute
02499      * @return  pointer     Result pointer
02500      * @deprecated since TYPO3 4.1, will be removed in TYPO3 4.6
02501      */
02502     public function sql($db, $query) {
02503         t3lib_div::logDeprecatedFunction();
02504 
02505         return $this->sql_query($query);
02506     }
02507 
02508     /**
02509      * Executes a query
02510      * EXPERIMENTAL - This method will make its best to handle the query correctly
02511      * but if it cannot, it will simply pass the query to DEFAULT handler.
02512      *
02513      * You should use exec_* function from this class instead!
02514      * If you don't, anything that does not use the _DEFAULT handler will probably break!
02515      *
02516      * This method was deprecated in TYPO3 4.1 but is considered experimental since TYPO3 4.4
02517      * as it tries to handle the query correctly anyway.
02518      *
02519      * @param   string      Query to execute
02520      * @return  pointer     Result pointer / DBAL object
02521      */
02522     public function sql_query($query) {
02523         $globalConfig = unserialize($GLOBALS['TYPO3_CONF_VARS']['EXT']['extConf']['dbal']);
02524         if ($globalConfig['sql_query.passthrough']) {
02525             return parent::sql_query($query);
02526         }
02527 
02528         // This method is heavily used by Extbase, try to handle it with DBAL-native methods
02529         $queryParts = $this->SQLparser->parseSQL($query);
02530         if (is_array($queryParts) && t3lib_div::inList('SELECT,UPDATE,INSERT,DELETE', $queryParts['type'])) {
02531             return $this->exec_query($queryParts);
02532         }
02533 
02534         switch ($this->handlerCfg['_DEFAULT']['type']) {
02535             case 'native':
02536                 $sqlResult = mysql_query($query, $this->handlerInstance['_DEFAULT']['link']);
02537                 break;
02538             case 'adodb':
02539                 $sqlResult = $this->handlerInstance['_DEFAULT']->Execute($query);
02540                 $sqlResult->TYPO3_DBAL_handlerType = 'adodb';
02541                 break;
02542             case 'userdefined':
02543                 $sqlResult = $this->handlerInstance['_DEFAULT']->sql_query($query);
02544                 $sqlResult->TYPO3_DBAL_handlerType = 'userdefined';
02545                 break;
02546         }
02547 
02548         if ($this->printErrors && $this->sql_error()) {
02549             debug(array($this->lastQuery, $this->sql_error()));
02550         }
02551 
02552         return $sqlResult;
02553     }
02554 
02555     /**
02556      * Opening the _DEFAULT connection handler to the database.
02557      * This is typically done by the scripts "init.php" in the backend or "index_ts.php" in the frontend (tslib_fe->connectToMySQL())
02558      * You wouldn't need to use this at any time - let TYPO3 core handle this.
02559      *
02560      * @param   string      Database host IP/domain
02561      * @param   string      Username to connect with.
02562      * @param   string      Password to connect with.
02563      * @return  mixed       Returns handler connection value
02564      * @see handler_init()
02565      */
02566     public function sql_pconnect($TYPO3_db_host, $TYPO3_db_username, $TYPO3_db_password) {
02567         // Overriding the _DEFAULT handler configuration of username, password, localhost and database name:
02568         $this->handlerCfg['_DEFAULT']['config']['username'] = $TYPO3_db_username;
02569         $this->handlerCfg['_DEFAULT']['config']['password'] = $TYPO3_db_password;
02570         $this->handlerCfg['_DEFAULT']['config']['host'] = $TYPO3_db_host;
02571         $this->handlerCfg['_DEFAULT']['config']['database'] = TYPO3_db;
02572 
02573         // Initializing and output value:
02574         $sqlResult = $this->handler_init('_DEFAULT');
02575         return $sqlResult;
02576     }
02577 
02578     /**
02579      * Select database for _DEFAULT handler.
02580      *
02581      * @param   string      Database to connect to.
02582      * @return  boolean     Always returns TRUE; function is obsolete, database selection is made in handler_init() function!
02583      */
02584     public function sql_select_db($TYPO3_db) {
02585         return TRUE;
02586     }
02587 
02588 
02589     /**************************************
02590      *
02591      * SQL admin functions
02592      * (For use in the Install Tool and Extension Manager)
02593      *
02594      **************************************/
02595 
02596     /**
02597      * Listing databases from current MySQL connection. NOTICE: It WILL try to select those databases and thus break selection of current database.
02598      * Use in Install Tool only!
02599      * Usage count/core: 1
02600      *
02601      * @return  array       Each entry represents a database name
02602      */
02603     public function admin_get_dbs() {
02604         $dbArr = array();
02605         switch ($this->handlerCfg['_DEFAULT']['type']) {
02606             case 'native':
02607                 $db_list = mysql_list_dbs($this->link);
02608                 while ($row = mysql_fetch_object($db_list)) {
02609                     if ($this->sql_select_db($row->Database)) {
02610                         $dbArr[] = $row->Database;
02611                     }
02612                 }
02613                 break;
02614             case 'adodb':
02615                 // check needed for install tool - otherwise it will just die because the call to
02616                 // MetaDatabases is done on a stdClass instance
02617                 if (method_exists($this->handlerInstance['_DEFAULT'], 'MetaDatabases')) {
02618                     $sqlDBs = $this->handlerInstance['_DEFAULT']->MetaDatabases();
02619                     if (is_array($sqlDBs)) {
02620                         foreach ($sqlDBs as $k => $theDB) {
02621                             $dbArr[] = $theDB;
02622                         }
02623                     }
02624                 }
02625                 break;
02626             case 'userdefined':
02627                 $dbArr = $this->handlerInstance['_DEFAULT']->admin_get_tables();
02628                 break;
02629         }
02630 
02631         return $dbArr;
02632     }
02633 
02634     /**
02635      * Returns the list of tables from the system (quering the DBMSs)
02636      * It looks up all tables from the DBMS of the _DEFAULT handler and then add all tables *configured* to be managed by other handlers
02637      *
02638      * When fetching the tables, it skips tables whose names begin with BIN$, as this is taken as a table coming from the "Recycle Bin" on Oracle.
02639      *
02640      * @return  array       Tables in an array (tablename is in both key and value)
02641      * @todo    Should the check for Oracle Recycle Bin stuff be moved elsewhere?
02642      * @todo    Should return table details in value! see t3lib_db::admin_get_tables()
02643      */
02644     public function admin_get_tables() {
02645         $whichTables = array();
02646 
02647         // Getting real list of tables:
02648         switch ($this->handlerCfg['_DEFAULT']['type']) {
02649             case 'native':
02650                 $tables_result = mysql_query('SHOW TABLE STATUS FROM `' . TYPO3_db . '`', $this->handlerInstance['_DEFAULT']['link']);
02651                 if (!$this->sql_error()) {
02652                     while ($theTable = $this->sql_fetch_assoc($tables_result)) {
02653                         $whichTables[$theTable['Name']] = $theTable;
02654                     }
02655                 }
02656                 break;
02657             case 'adodb':
02658                 // check needed for install tool - otherwise it will just die because the call to
02659                 // MetaTables is done on a stdClass instance
02660                 if (method_exists($this->handlerInstance['_DEFAULT'], 'MetaTables')) {
02661                     $sqlTables = $this->handlerInstance['_DEFAULT']->MetaTables('TABLES');
02662                     while (list($k, $theTable) = each($sqlTables)) {
02663                         if (preg_match('/BIN\$/', $theTable)) continue; // skip tables from the Oracle 10 Recycle Bin
02664                         $whichTables[$theTable] = $theTable;
02665                     }
02666                 }
02667                 break;
02668             case 'userdefined':
02669                 $whichTables = $this->handlerInstance['_DEFAULT']->admin_get_tables();
02670                 break;
02671         }
02672 
02673         // Check mapping:
02674         if (is_array($this->mapping) && count($this->mapping)) {
02675 
02676             // Mapping table names in reverse, first getting list of real table names:
02677             $tMap = array();
02678             foreach ($this->mapping as $tN => $tMapInfo) {
02679                 if (isset($tMapInfo['mapTableName'])) {
02680                     $tMap[$tMapInfo['mapTableName']] = $tN;
02681                 }
02682             }
02683 
02684             // Do mapping:
02685             $newList = array();
02686             foreach ($whichTables as $tN => $tDefinition) {
02687                 if (isset($tMap[$tN])) {
02688                     $tN = $tMap[$tN];
02689                 }
02690                 $newList[$tN] = $tDefinition;
02691             }
02692 
02693             $whichTables = $newList;
02694         }
02695 
02696         // Adding tables configured to reside in other DBMS (handler by other handlers than the default):
02697         if (is_array($this->table2handlerKeys)) {
02698             foreach ($this->table2handlerKeys as $key => $handlerKey) {
02699                 $whichTables[$key] = $key;
02700             }
02701         }
02702 
02703         return $whichTables;
02704     }
02705 
02706     /**
02707      * Returns information about each field in the $table (quering the DBMS)
02708      * In a DBAL this should look up the right handler for the table and return compatible information
02709      * 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
02710      *
02711      * @param   string      Table name
02712      * @return  array       Field information in an associative array with fieldname => field row
02713      */
02714     public function admin_get_fields($tableName) {
02715         $output = array();
02716 
02717         // Do field mapping if needed:
02718         $ORIG_tableName = $tableName;
02719         if ($tableArray = $this->map_needMapping($tableName)) {
02720 
02721             // Table name:
02722             if ($this->mapping[$tableName]['mapTableName']) {
02723                 $tableName = $this->mapping[$tableName]['mapTableName'];
02724             }
02725         }
02726 
02727         // Find columns
02728         $this->lastHandlerKey = $this->handler_getFromTableList($ORIG_tableName);
02729         switch ((string) $this->handlerCfg[$this->lastHandlerKey]['type']) {
02730             case 'native':
02731                 $columns_res = mysql_query('SHOW columns FROM ' . $tableName, $this->handlerInstance[$this->lastHandlerKey]['link']);
02732                 while ($fieldRow = mysql_fetch_assoc($columns_res)) {
02733                     $output[$fieldRow['Field']] = $fieldRow;
02734                 }
02735                 break;
02736             case 'adodb':
02737                 $fieldRows = $this->handlerInstance[$this->lastHandlerKey]->MetaColumns($tableName, FALSE);
02738                 if (is_array($fieldRows)) {
02739                     foreach ($fieldRows as $k => $fieldRow) {
02740                         settype($fieldRow, 'array');
02741                         $fieldRow['Field'] = $fieldRow['name'];
02742                         $ntype = $this->MySQLActualType($this->MetaType($fieldRow['type'], $tableName));
02743                         $ntype .= (($fieldRow['max_length'] != -1) ? (($ntype == 'INT') ? '(11)' : '(' . $fieldRow['max_length'] . ')') : '');
02744                         $fieldRow['Type'] = strtolower($ntype);
02745                         $fieldRow['Null'] = '';
02746                         $fieldRow['Key'] = '';
02747                         $fieldRow['Default'] = $fieldRow['default_value'];
02748                         $fieldRow['Extra'] = '';
02749                         $output[$fieldRow['name']] = $fieldRow;
02750                     }
02751                 }
02752                 break;
02753             case 'userdefined':
02754                 $output = $this->handlerInstance[$this->lastHandlerKey]->admin_get_fields($tableName);
02755                 break;
02756         }
02757 
02758         // mapping should be done:
02759         if (is_array($tableArray) && is_array($this->mapping[$ORIG_tableName]['mapFieldNames'])) {
02760             $revFields = array_flip($this->mapping[$ORIG_tableName]['mapFieldNames']);
02761 
02762             $newOutput = array();
02763             foreach ($output as $fN => $fInfo) {
02764                 if (isset($revFields[$fN])) {
02765                     $fN = $revFields[$fN];
02766                     $fInfo['Field'] = $fN;
02767                 }
02768                 $newOutput[$fN] = $fInfo;
02769             }
02770             $output = $newOutput;
02771         }
02772 
02773         return $output;
02774     }
02775 
02776     /**
02777      * Returns information about each index key in the $table (quering the DBMS)
02778      * In a DBAL this should look up the right handler for the table and return compatible information
02779      *
02780      * @param   string      Table name
02781      * @return  array       Key information in a numeric array
02782      */
02783     public function admin_get_keys($tableName) {
02784         $output = array();
02785 
02786         // Do field mapping if needed:
02787         $ORIG_tableName = $tableName;
02788         if ($tableArray = $this->map_needMapping($tableName)) {
02789 
02790             // Table name:
02791             if ($this->mapping[$tableName]['mapTableName']) {
02792                 $tableName = $this->mapping[$tableName]['mapTableName'];
02793             }
02794         }
02795 
02796         // Find columns
02797         $this->lastHandlerKey = $this->handler_getFromTableList($ORIG_tableName);
02798         switch ((string) $this->handlerCfg[$this->lastHandlerKey]['type']) {
02799             case 'native':
02800                 $keyRes = mysql_query('SHOW keys FROM ' . $tableName, $this->handlerInstance[$this->lastHandlerKey]['link']);
02801                 while ($keyRow = mysql_fetch_assoc($keyRes)) {
02802                     $output[] = $keyRow;
02803                 }
02804                 break;
02805             case 'adodb':
02806                 $keyRows = $this->handlerInstance[$this->lastHandlerKey]->MetaIndexes($tableName);
02807                 if ($keyRows !== FALSE) {
02808                     while (list($k, $theKey) = each($keyRows)) {
02809                         $theKey['Table'] = $tableName;
02810                         $theKey['Non_unique'] = (int) !$theKey['unique'];
02811                         $theKey['Key_name'] = str_replace($tableName . '_', '', $k);
02812 
02813                         // the following are probably not needed anyway...
02814                         $theKey['Collation'] = '';
02815                         $theKey['Cardinality'] = '';
02816                         $theKey['Sub_part'] = '';
02817                         $theKey['Packed'] = '';
02818                         $theKey['Null'] = '';
02819                         $theKey['Index_type'] = '';
02820                         $theKey['Comment'] = '';
02821 
02822                         // now map multiple fields into multiple rows (we mimic MySQL, remember...)
02823                         $keycols = $theKey['columns'];
02824                         while (list($c, $theCol) = each($keycols)) {
02825                             $theKey['Seq_in_index'] = $c + 1;
02826                             $theKey['Column_name'] = $theCol;
02827                             $output[] = $theKey;
02828                         }
02829                     }
02830                 }
02831                 $priKeyRow = $this->handlerInstance[$this->lastHandlerKey]->MetaPrimaryKeys($tableName);
02832                 $theKey = array();
02833                 $theKey['Table'] = $tableName;
02834                 $theKey['Non_unique'] = 0;
02835                 $theKey['Key_name'] = 'PRIMARY';
02836 
02837                 // the following are probably not needed anyway...
02838                 $theKey['Collation'] = '';
02839                 $theKey['Cardinality'] = '';
02840                 $theKey['Sub_part'] = '';
02841                 $theKey['Packed'] = '';
02842                 $theKey['Null'] = '';
02843                 $theKey['Index_type'] = '';
02844                 $theKey['Comment'] = '';
02845 
02846                 // now map multiple fields into multiple rows (we mimic MySQL, remember...)
02847                 if ($priKeyRow !== FALSE) {
02848                     while (list($c, $theCol) = each($priKeyRow)) {
02849                         $theKey['Seq_in_index'] = $c + 1;
02850                         $theKey['Column_name'] = $theCol;
02851                         $output[] = $theKey;
02852                     }
02853                 }
02854                 break;
02855             case 'userdefined':
02856                 $output = $this->handlerInstance[$this->lastHandlerKey]->admin_get_keys($tableName);
02857                 break;
02858         }
02859 
02860         // mapping should be done:
02861         if (is_array($tableArray) && is_array($this->mapping[$ORIG_tableName]['mapFieldNames'])) {
02862             $revFields = array_flip($this->mapping[$ORIG_tableName]['mapFieldNames']);
02863 
02864             $newOutput = array();
02865             foreach ($output as $kN => $kInfo) {
02866                 // Table:
02867                 $kInfo['Table'] = $ORIG_tableName;
02868 
02869                 // Column
02870                 if (isset($revFields[$kInfo['Column_name']])) {
02871                     $kInfo['Column_name'] = $revFields[$kInfo['Column_name']];
02872                 }
02873 
02874                 // Write it back:
02875                 $newOutput[$kN] = $kInfo;
02876             }
02877             $output = $newOutput;
02878         }
02879 
02880         return $output;
02881     }
02882 
02883     /**
02884      * mysql() wrapper function, used by the Install Tool.
02885      *
02886      * @return  array
02887      */
02888     public function admin_get_charsets() {
02889         return array();
02890     }
02891 
02892     /**
02893      * mysql() wrapper function, used by the Install Tool and EM for all queries regarding management of the database!
02894      *
02895      * @param   string      Query to execute
02896      * @return  pointer     Result pointer
02897      */
02898     public function admin_query($query) {
02899         $parsedQuery = $this->SQLparser->parseSQL($query);
02900         $ORIG_table = $parsedQuery['TABLE'];
02901 
02902         if (is_array($parsedQuery)) {
02903 
02904             // Process query based on type:
02905             switch ($parsedQuery['type']) {
02906                 case 'CREATETABLE':
02907                 case 'ALTERTABLE':
02908                 case 'DROPTABLE':
02909                     if (file_exists(PATH_typo3conf . 'temp_fieldInfo.php')) unlink(PATH_typo3conf . 'temp_fieldInfo.php');
02910                     $this->map_genericQueryParsed($parsedQuery);
02911                     break;
02912                 case 'INSERT':
02913                 case 'TRUNCATETABLE':
02914                     $this->map_genericQueryParsed($parsedQuery);
02915                     break;
02916                 case 'CREATEDATABASE':
02917                     die('Creating a database with DBAL is not supported. Did you really read the manual?');
02918                     break;
02919                 default:
02920                     die('ERROR: Invalid Query type (' . $parsedQuery['type'] . ') for ->admin_query() function!: "' . htmlspecialchars($query) . '"');
02921                     break;
02922             }
02923 
02924             // Setting query array (for other applications to access if needed)
02925             $this->lastParsedAndMappedQueryArray = $parsedQuery;
02926 
02927             // Execute query (based on handler derived from the TABLE name which we actually know for once!)
02928             $this->lastHandlerKey = $this->handler_getFromTableList($ORIG_table);
02929             switch ((string) $this->handlerCfg[$this->lastHandlerKey]['type']) {
02930                 case 'native':
02931                     // Compiling query:
02932                     $compiledQuery = $this->SQLparser->compileSQL($this->lastParsedAndMappedQueryArray);
02933 
02934                     //if ($this->lastParsedAndMappedQueryArray['type'] == 'INSERT') {
02935                     //  return mysql_query($compiledQuery, $this->link);
02936                     //}
02937                     return mysql_query($compiledQuery, $this->link);
02938                     break;
02939                 case 'adodb':
02940                     // Compiling query:
02941                     $compiledQuery = $this->SQLparser->compileSQL($this->lastParsedAndMappedQueryArray);
02942                     switch ($this->lastParsedAndMappedQueryArray['type']) {
02943                         case 'INSERT':
02944                             return $this->exec_INSERTquery($this->lastParsedAndMappedQueryArray['TABLE'], $compiledQuery);
02945                         case 'TRUNCATETABLE':
02946                             return $this->exec_TRUNCATEquery($this->lastParsedAndMappedQueryArray['TABLE']);
02947                     }
02948                     return $this->handlerInstance[$this->lastHandlerKey]->DataDictionary->ExecuteSQLArray($compiledQuery);
02949                     break;
02950                 case 'userdefined':
02951                     // Compiling query:
02952                     $compiledQuery = $this->SQLparser->compileSQL($this->lastParsedAndMappedQueryArray);
02953 
02954                     return $this->handlerInstance[$this->lastHandlerKey]->admin_query($compiledQuery);
02955                     break;
02956             }
02957         } else die('ERROR: Query could not be parsed: "' . htmlspecialchars($parsedQuery) . '". Query: "' . htmlspecialchars($query) . '"');
02958     }
02959 
02960 
02961     /************************************
02962      *
02963      * Handler management
02964      *
02965      **************************************/
02966 
02967     /**
02968      * Return the handler key pointing to an appropriate database handler as found in $this->handlerCfg array
02969      * 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!)
02970      *
02971      * @param   string      Table list, eg. "pages" or "pages, tt_content" or "pages AS A, tt_content AS B"
02972      * @return  string      Handler key (see $this->handlerCfg array) for table
02973      */
02974     public function handler_getFromTableList($tableList) {
02975 
02976         $key = $tableList;
02977 
02978         if (!isset($this->cache_handlerKeyFromTableList[$key])) {
02979 
02980             // Get tables separated:
02981             $_tableList = $tableList;
02982             $tableArray = $this->SQLparser->parseFromTables($_tableList);
02983 
02984             // If success, traverse the tables:
02985             if (is_array($tableArray) && count($tableArray)) {
02986                 $outputHandlerKey = '';
02987 
02988                 foreach ($tableArray as $vArray) {
02989                     // Find handler key, select "_DEFAULT" if none is specifically configured:
02990                     $handlerKey = $this->table2handlerKeys[$vArray['table']] ? $this->table2handlerKeys[$vArray['table']] : '_DEFAULT';
02991 
02992                     // In case of separate handler keys for joined tables:
02993                     if ($outputHandlerKey && $handlerKey != $outputHandlerKey) {
02994                         die('DBAL fatal error: Tables in this list "' . $tableList . '" didn\'t use the same DB handler!');
02995                     }
02996 
02997                     $outputHandlerKey = $handlerKey;
02998                 }
02999 
03000                 // Check initialized state; if handler is NOT initialized (connected) then we will connect it!
03001                 if (!isset($this->handlerInstance[$outputHandlerKey])) {
03002                     $this->handler_init($outputHandlerKey);
03003                 }
03004 
03005                 // Return handler key:
03006                 $this->cache_handlerKeyFromTableList[$key] = $outputHandlerKey;
03007             } else {
03008                 die('DBAL fatal error: No handler found in handler_getFromTableList() for: "' . $tableList . '" (' . $tableArray . ')');
03009             }
03010         }
03011 
03012         return $this->cache_handlerKeyFromTableList[$key];
03013     }
03014 
03015     /**
03016      * Initialize handler (connecting to database)
03017      *
03018      * @param   string      Handler key
03019      * @return  boolean     If connection went well, return TRUE
03020      * @see handler_getFromTableList()
03021      */
03022     public function handler_init($handlerKey) {
03023 
03024         // Find handler configuration:
03025         $cfgArray = $this->handlerCfg[$handlerKey];
03026         $handlerType = (string) $cfgArray['type'];
03027         $output = FALSE;
03028 
03029         if (is_array($cfgArray)) {
03030             if (!$cfgArray['config']['database']) {
03031                 // Configuration is incomplete
03032                 return;
03033             }
03034             switch ($handlerType) {
03035                 case 'native':
03036                     if ($GLOBALS['TYPO3_CONF_VARS']['SYS']['no_pconnect']) {
03037                         $link = mysql_connect($cfgArray['config']['host'] . (isset($cfgArray['config']['port']) ? ':' . $cfgArray['config']['port'] : ''), $cfgArray['config']['username'], $cfgArray['config']['password'], TRUE);
03038                     } else {
03039                         $link = mysql_pconnect($cfgArray['config']['host'] . (isset($cfgArray['config']['port']) ? ':' . $cfgArray['config']['port'] : ''), $cfgArray['config']['username'], $cfgArray['config']['password']);
03040                     }
03041 
03042                     // Set handler instance:
03043                     $this->handlerInstance[$handlerKey] = array('handlerType' => 'native', 'link' => $link);
03044 
03045                     // If link succeeded:
03046                     if ($link) {
03047                         // For default, set ->link (see t3lib_DB)
03048                         if ($handlerKey == '_DEFAULT') {
03049                             $this->link = $link;
03050                         }
03051 
03052                         // Select database as well:
03053                         if (mysql_select_db($cfgArray['config']['database'], $link)) {
03054                             $output = TRUE;
03055                         }
03056                         $setDBinit = t3lib_div::trimExplode(LF, str_replace("' . LF . '", LF, $GLOBALS['TYPO3_CONF_VARS']['SYS']['setDBinit']), TRUE);
03057                         foreach ($setDBinit as $v) {
03058                             if (mysql_query($v, $link) === FALSE) {
03059                                 t3lib_div::sysLog('Could not initialize DB connection with query "' . $v . '".', 'Core', 3);
03060                             }
03061                         }
03062                     } else {
03063                         t3lib_div::sysLog('Could not connect to MySQL server ' . $cfgArray['config']['host'] . ' with user ' . $cfgArray['config']['username'] . '.', 'Core', 4);
03064                     }
03065                     break;
03066                 case 'adodb':
03067                     $output = TRUE;
03068                     require_once(t3lib_extMgm::extPath('adodb') . 'adodb/adodb.inc.php');
03069                     if (!defined('ADODB_FORCE_NULLS')) define('ADODB_FORCE_NULLS', 1);
03070                     $GLOBALS['ADODB_FORCE_TYPE'] = ADODB_FORCE_VALUE;
03071                     $GLOBALS['ADODB_FETCH_MODE'] = ADODB_FETCH_BOTH;
03072 
03073                     $this->handlerInstance[$handlerKey] = &ADONewConnection($cfgArray['config']['driver']);
03074 
03075                     // Set driver-specific options
03076                     if (isset($cfgArray['config']['driverOptions'])) {
03077                         foreach ($cfgArray['config']['driverOptions'] as $optionName => $optionValue) {
03078                             $optionSetterName = 'set' . ucfirst($optionName);
03079                             if (method_exists($this->handlerInstance[$handlerKey], $optionSetterName)) {
03080                                 $this->handlerInstance[$handlerKey]->$optionSetterName($optionValue);
03081                             } else {
03082                                 $this->handlerInstance[$handlerKey]->$optionName = $optionValue;
03083                             }
03084                         }
03085                     }
03086 
03087                     if ($GLOBALS['TYPO3_CONF_VARS']['SYS']['no_pconnect']) {
03088                         $this->handlerInstance[$handlerKey]->Connect($cfgArray['config']['host'] . (isset($cfgArray['config']['port']) ? ':' . $cfgArray['config']['port'] : ''), $cfgArray['config']['username'], $cfgArray['config']['password'], $cfgArray['config']['database']);
03089                     } else {
03090                         $this->handlerInstance[$handlerKey]->PConnect($cfgArray['config']['host'] . (isset($cfgArray['config']['port']) ? ':' . $cfgArray['config']['port'] : ''), $cfgArray['config']['username'], $cfgArray['config']['password'], $cfgArray['config']['database']);
03091                     }
03092                     if (!$this->handlerInstance[$handlerKey]->isConnected()) {
03093                         $dsn = $cfgArray['config']['driver'] . '://' . $cfgArray['config']['username'] .
03094                                 (strlen($cfgArray['config']['password']) ? ':XXXX@' : '') .
03095                                 $cfgArray['config']['host'] . (isset($cfgArray['config']['port']) ? ':' . $cfgArray['config']['port'] : '') . '/' . $cfgArray['config']['database'] .
03096                                 ($GLOBALS['TYPO3_CONF_VARS']['SYS']['no_pconnect'] ? '' : '?persistent=1');
03097                         t3lib_div::sysLog('Could not connect to DB server using ADOdb on ' . $cfgArray['config']['host'] . ' with user ' . $cfgArray['config']['username'] . '.', 'Core', 4);
03098                         error_log('DBAL error: Connection to ' . $dsn . ' failed. Maybe PHP doesn\'t support the database?');
03099                         $output = FALSE;
03100                     } else {
03101                         $this->handlerInstance[$handlerKey]->DataDictionary = NewDataDictionary($this->handlerInstance[$handlerKey]);
03102                         $this->handlerInstance[$handlerKey]->last_insert_id = 0;
03103                         if (isset($cfgArray['config']['sequenceStart'])) {
03104                             $this->handlerInstance[$handlerKey]->sequenceStart = $cfgArray['config']['sequenceStart'];
03105                         } else {
03106                             $this->handlerInstance[$handlerKey]->sequenceStart = 1;
03107                         }
03108                     }
03109                     break;
03110                 case 'userdefined':
03111                     // Find class file:
03112                     $fileName = t3lib_div::getFileAbsFileName($cfgArray['config']['classFile']);
03113                     if (@is_file($fileName)) {
03114                         require_once($fileName);
03115                     } else die('DBAL error: "' . $fileName . '" was not a file to include.');
03116 
03117                     // Initialize:
03118                     $this->handlerInstance[$handlerKey] = t3lib_div::makeInstance($cfgArray['config']['class']);
03119                     $this->handlerInstance[$handlerKey]->init($cfgArray, $this);
03120 
03121                     if (is_object($this->handlerInstance[$handlerKey])) {
03122                         $output = TRUE;
03123                     }
03124                     break;
03125                 default:
03126                     die('ERROR: Invalid handler type: "' . $cfgArray['type'] . '"');
03127                     break;
03128             }
03129 
03130             return $output;
03131         } else die('ERROR: No handler for key "' . $handlerKey . '"');
03132     }
03133 
03134 
03135     /**
03136      * Checks if database is connected.
03137      *
03138      * @return boolean
03139      */
03140     public function isConnected() {
03141         $result = FALSE;
03142         switch ((string) $this->handlerCfg[$this->lastHandlerKey]['type']) {
03143             case 'native':
03144                 $result = is_resource($this->link);
03145                 break;
03146             case 'adodb':
03147             case 'userdefined':
03148                 $result = is_object($this->handlerInstance[$this->lastHandlerKey]) && $this->handlerInstance[$this->lastHandlerKey]->isConnected();
03149                 break;
03150         }
03151         return $result;
03152     }
03153 
03154 
03155     /**
03156      * Checks whether the DBAL is currently inside an operation running on the "native" DB handler (i.e. MySQL)
03157      *
03158      * @return boolean  True if running on "native" DB handler (i.e. MySQL)
03159      */
03160     public function runningNative() {
03161         return ((string) $this->handlerCfg[$this->lastHandlerKey]['type']==='native');
03162     }
03163 
03164 
03165     /**
03166      * Checks whether the ADOdb handler is running with a driver that contains the argument
03167      *
03168      * @param string    $driver Driver name, matched with strstr().
03169      * @return boolean  True if running with the given driver
03170      */
03171     public function runningADOdbDriver($driver) {
03172         return strstr($this->handlerCfg[$this->lastHandlerKey]['config']['driver'], $driver);
03173     }
03174 
03175 
03176     /************************************
03177      *
03178      * Table/Field mapping
03179      *
03180      **************************************/
03181 
03182     /**
03183      * Checks if mapping is needed for a table(list)
03184      *
03185      * @param   string      List of tables in query
03186      * @param   boolean     If TRUE, it will check only if FIELDs are configured and ignore the mapped table name if any.
03187      * @param   array       Parsed list of tables, should be passed as reference to be reused and prevent double parsing
03188      * @return  mixed       Returns an array of table names (parsed version of input table) if mapping is needed, otherwise just FALSE.
03189      */
03190     protected function map_needMapping($tableList, $fieldMappingOnly = FALSE, array &$parsedTableList = array()) {
03191         $key = $tableList . '|' . $fieldMappingOnly;
03192         if (!isset($this->cache_mappingFromTableList[$key])) {
03193             $this->cache_mappingFromTableList[$key] = FALSE; // Default:
03194 
03195             $tables = $this->SQLparser->parseFromTables($tableList);
03196             if (is_array($tables)) {
03197                 $parsedTableList = $tables;
03198                 foreach ($tables as $tableCfg) {
03199                     if ($fieldMappingOnly) {
03200                         if (is_array($this->mapping[$tableCfg['table']]['mapFieldNames'])) {
03201                             $this->cache_mappingFromTableList[$key] = $tables;
03202                         } elseif (is_array($tableCfg['JOIN'])) {
03203                             foreach ($tableCfg['JOIN'] as $join) {
03204                                 if (is_array($this->mapping[$join['withTable']]['mapFieldNames'])) {
03205                                     $this->cache_mappingFromTableList[$key] = $tables;
03206                                     break;
03207                                 }
03208                             }
03209                         }
03210                     } else {
03211                         if (is_array($this->mapping[$tableCfg['table']])) {
03212                             $this->cache_mappingFromTableList[$key] = $tables;
03213                         } elseif (is_array($tableCfg['JOIN'])) {
03214                             foreach ($tableCfg['JOIN'] as $join) {
03215                                 if (is_array($this->mapping[$join['withTable']])) {
03216                                     $this->cache_mappingFromTableList[$key] = $tables;
03217                                     break;
03218                                 }
03219                             }
03220                         }
03221                     }
03222                 }
03223             }
03224         }
03225 
03226         return $this->cache_mappingFromTableList[$key];
03227     }
03228 
03229     /**
03230      * Takes an associated array with field => value pairs and remaps the field names if configured for this table in $this->mapping array.
03231      * Be careful not to map a field name to another existing fields name (although you can use this to swap fieldnames of course...:-)
03232      * Observe mapping problems with join-results (more than one table): Joined queries should always prefix the table name to avoid problems with this.
03233      * Observe that alias fields are not mapped of course (should not be a problem though)
03234      *
03235      * @param   array       Input array, associative keys
03236      * @param   array       Array of tables from the query. Normally just one table; many tables in case of a join. NOTICE: for multiple tables (with joins) there MIGHT occur trouble with fields of the same name in the two tables: This function traverses the mapping information for BOTH tables and applies mapping without checking from which table the field really came!
03237      * @param   boolean     If TRUE, reverse direction. Default direction is to map an array going INTO the database (thus mapping TYPO3 fieldnames to PHYSICAL field names!)
03238      * @return  array       Output array, with mapped associative keys.
03239      */
03240     protected function map_assocArray($input, $tables, $rev = FALSE) {
03241         // Traverse tables from query (hopefully only one table):
03242         foreach ($tables as $tableCfg) {
03243             $tableKey = $this->getMappingKey($tableCfg['table']);
03244             if (is_array($this->mapping[$tableKey]['mapFieldNames'])) {
03245 
03246                 // Get the map (reversed if needed):
03247                 if ($rev) {
03248                     $theMap = array_flip($this->mapping[$tableKey]['mapFieldNames']);
03249                 } else {
03250                     $theMap = $this->mapping[$tableKey]['mapFieldNames'];
03251                 }
03252 
03253                 // Traverse selected record, map fieldnames:
03254                 $output = array();
03255                 foreach ($input as $fN => $value) {
03256 
03257                     // Set the field name, change it if found in mapping array:
03258                     if ($theMap[$fN]) {
03259                         $newKey = $theMap[$fN];
03260                     } else {
03261                         $newKey = $fN;
03262                     }
03263 
03264                     // Set value to fieldname:
03265                     $output[$newKey] = $value;
03266                 }
03267 
03268                 // When done, override the $input array with the result:
03269                 $input = $output;
03270             }
03271         }
03272 
03273         // Return input array (which might have been altered in the mean time)
03274         return $input;
03275     }
03276 
03277     /**
03278      * Remaps table/field names in a SELECT query's parts
03279      *
03280      * @param   mixed       Either parsed list of tables (SQLparser->parseFromTables()) or list of fields to select from the table. This is what comes right after "SELECT ...". Required value.
03281      * @param   string      Table(s) from which to select. This is what comes right after "FROM ...". Require value.
03282      * @param   string      Where clause. This is what comes right after "WHERE ...". Can be blank.
03283      * @param   string      Group by field(s)
03284      * @param   string      Order by field(s)
03285      * @return  void
03286      * @see exec_SELECTquery()
03287      */
03288     protected function map_remapSELECTQueryParts($select_fields, $from_table, $where_clause, $groupBy, $orderBy) {
03289         // Backup current mapping as it may be altered if aliases on mapped tables are found
03290         $backupMapping = $this->mapping;
03291 
03292         // Tables:
03293         $tables = is_array($from_table) ? $from_table : $this->SQLparser->parseFromTables($from_table);
03294         $defaultTable = $tables[0]['table'];
03295         // Prepare mapping for aliased tables. This will copy the definition of the original table name.
03296         // The alias is prefixed with a database-incompatible character to prevent naming clash with real table name
03297         // Further access to $this->mapping should be made through $this->getMappingKey() method
03298         foreach ($tables as $k => $v) {
03299             if ($v['as'] && is_array($this->mapping[$v['table']]['mapFieldNames'])) {
03300                 $mappingKey = $this->getFreeMappingKey($v['as']);
03301                 $this->mapping[$mappingKey]['mapFieldNames'] =& $this->mapping[$v['table']]['mapFieldNames'];
03302             }
03303             if (is_array($v['JOIN'])) {
03304                 foreach ($v['JOIN'] as $joinCnt => $join) {
03305                     if ($join['as'] && is_array($this->mapping[$join['withTable']]['mapFieldNames'])) {
03306                         $mappingKey = $this->getFreeMappingKey($join['as']);
03307                         $this->mapping[$mappingKey]['mapFieldNames'] =& $this->mapping[$join['withTable']]['mapFieldNames'];
03308                     }
03309                 }
03310             }
03311         }
03312         foreach ($tables as $k => $v) {
03313             $tableKey = $this->getMappingKey($v['table']);
03314             if ($this->mapping[$tableKey]['mapTableName']) {
03315                 $tables[$k]['table'] = $this->mapping[$tableKey]['mapTableName'];
03316             }
03317             // Mapping JOINS
03318             if (is_array($v['JOIN'])) {
03319                 foreach ($v['JOIN'] as $joinCnt => $join) {
03320                     // Mapping withTable of the JOIN
03321                     $withTableKey = $this->getMappingKey($join['withTable']);
03322                     if ($this->mapping[$withTableKey]['mapTableName']) {
03323                         $tables[$k]['JOIN'][$joinCnt]['withTable'] = $this->mapping[$withTableKey]['mapTableName'];
03324                     }
03325                     $onPartsArray = array();
03326                     // Mapping ON parts of the JOIN
03327                     if (is_array($tables[$k]['JOIN'][$joinCnt]['ON'])) {
03328                         foreach ($tables[$k]['JOIN'][$joinCnt]['ON'] as &$condition) {
03329                             // Left side of the comparator
03330                             $leftTableKey = $this->getMappingKey($condition['left']['table']);
03331                             if (isset($this->mapping[$leftTableKey]['mapFieldNames'][$condition['left']['field']])) {
03332                                 $condition['left']['field'] = $this->mapping[$leftTableKey]['mapFieldNames'][$condition['left']['field']];
03333                             }
03334                             if (isset($this->mapping[$leftTableKey]['mapTableName'])) {
03335                                 $condition['left']['table'] = $this->mapping[$leftTableKey]['mapTableName'];
03336                             }
03337                             // Right side of the comparator
03338                             $rightTableKey = $this->getMappingKey($condition['right']['table']);
03339                             if (isset($this->mapping[$rightTableKey]['mapFieldNames'][$condition['right']['field']])) {
03340                                 $condition['right']['field'] = $this->mapping[$rightTableKey]['mapFieldNames'][$condition['right']['field']];
03341                             }
03342                             if (isset($this->mapping[$rightTableKey]['mapTableName'])) {
03343                                 $condition['right']['table'] = $this->mapping[$rightTableKey]['mapTableName'];
03344                             }
03345                         }
03346                     }
03347                 }
03348             }
03349         }
03350         $fromParts = $tables;
03351 
03352         // Where clause:
03353         $parameterReferences = array();
03354         $whereParts = $this->SQLparser->parseWhereClause($where_clause, '', $parameterReferences);
03355         $this->map_sqlParts($whereParts, $defaultTable);
03356 
03357         // Select fields:
03358         $selectParts = $this->SQLparser->parseFieldList($select_fields);
03359         $this->map_sqlParts($selectParts, $defaultTable);
03360 
03361         // Group By fields
03362         $groupByParts = $this->SQLparser->parseFieldList($groupBy);
03363         $this->map_sqlParts($groupByParts, $defaultTable);
03364 
03365         // Order By fields
03366         $orderByParts = $this->SQLparser->parseFieldList($orderBy);
03367         $this->map_sqlParts($orderByParts, $defaultTable);
03368 
03369         // Restore the original mapping
03370         $this->mapping = $backupMapping;
03371 
03372         return array($selectParts, $fromParts, $whereParts, $groupByParts, $orderByParts, $parameterReferences);
03373     }
03374 
03375     /**
03376      * Returns the key to be used when retrieving information from $this->mapping. This ensures
03377      * that mapping from aliased tables is properly retrieved.
03378      *
03379      * @param string $tableName
03380      * @return string
03381      */
03382     protected function getMappingKey($tableName) {
03383         // Search deepest alias mapping
03384         while (isset($this->mapping['*' . $tableName])) {
03385             $tableName = '*' . $tableName;
03386         }
03387         return $tableName;
03388     }
03389 
03390     /**
03391      * Returns a free key to be used to store mapping information in $this->mapping.
03392      *
03393      * @param string $tableName
03394      * @return string
03395      */
03396     protected function getFreeMappingKey($tableName) {
03397         while (isset($this->mapping[$tableName])) {
03398             $tableName = '*' . $tableName;
03399         }
03400         return $tableName;
03401     }
03402 
03403     /**
03404      * Generic mapping of table/field names arrays (as parsed by tx_dbal_sqlengine)
03405      *
03406      * @param   array       Array with parsed SQL parts; Takes both fields, tables, where-parts, group and order-by. Passed by reference.
03407      * @param   string      Default table name to assume if no table is found in $sqlPartArray
03408      * @return  void
03409      * @access private
03410      * @see map_remapSELECTQueryParts()
03411      */
03412     protected function map_sqlParts(&$sqlPartArray, $defaultTable) {
03413         $defaultTableKey = $this->getMappingKey($defaultTable);
03414         // Traverse sql Part array:
03415         if (is_array($sqlPartArray)) {
03416             foreach ($sqlPartArray as $k => $v) {
03417 
03418                 if (isset($sqlPartArray[$k]['type'])) {
03419                     switch ($sqlPartArray[$k]['type']) {
03420                         case 'flow-control':
03421                             $temp = array($sqlPartArray[$k]['flow-control']);
03422                             $this->map_sqlParts($temp, $defaultTable); // Call recursively!
03423                             $sqlPartArray[$k]['flow-control'] = $temp[0];
03424                             break;
03425                         case 'CASE':
03426                             if (isset($sqlPartArray[$k]['case_field'])) {
03427                                 $fieldArray = explode('.', $sqlPartArray[$k]['case_field']);
03428                                 if (count($fieldArray) == 1 && is_array($this->mapping[$defaultTableKey]['mapFieldNames']) && isset($this->mapping[$defaultTableKey]['mapFieldNames'][$fieldArray[0]])) {
03429                                     $sqlPartArray[$k]['case_field'] = $this->mapping[$defaultTableKey]['mapFieldNames'][$fieldArray[0]];
03430                                 }
03431                                 elseif (count($fieldArray) == 2) {
03432                                     // Map the external table
03433                                     $table = $fieldArray[0];
03434                                     $tableKey = $this->getMappingKey($table);
03435                                     if (isset($this->mapping[$tableKey]['mapTableName'])) {
03436                                         $table = $this->mapping[$tableKey]['mapTableName'];
03437                                     }
03438                                     // Map the field itself
03439                                     $field = $fieldArray[1];
03440                                     if (is_array($this->mapping[$tableKey]['mapFieldNames']) && isset($this->mapping[$tableKey]['mapFieldNames'][$fieldArray[1]])) {
03441                                         $field = $this->mapping[$tableKey]['mapFieldNames'][$fieldArray[1]];
03442                                     }
03443                                     $sqlPartArray[$k]['case_field'] = $table . '.' . $field;
03444                                 }
03445                             }
03446                             foreach ($sqlPartArray[$k]['when'] as $key => $when) {
03447                                 $this->map_sqlParts($sqlPartArray[$k]['when'][$key]['when_value'], $defaultTable);
03448                             }
03449                             break;
03450                     }
03451                 }
03452 
03453                 // Look for sublevel (WHERE parts only)
03454                 if (is_array($sqlPartArray[$k]['sub'])) {
03455                     $this->map_sqlParts($sqlPartArray[$k]['sub'], $defaultTable); // Call recursively!
03456                 } elseif (isset($sqlPartArray[$k]['func'])) {
03457                     switch ($sqlPartArray[$k]['func']['type']) {
03458                         case 'EXISTS':
03459                             $this->map_subquery($sqlPartArray[$k]['func']['subquery']);
03460                             break;
03461                         case 'FIND_IN_SET':
03462                         case 'IFNULL':
03463                         case 'LOCATE':
03464                             // For the field, look for table mapping (generic):
03465                             $t = $sqlPartArray[$k]['func']['table'] ? $sqlPartArray[$k]['func']['table'] : $defaultTable;
03466                             $t = $this->getMappingKey($t);
03467                             if (is_array($this->mapping[$t]['mapFieldNames']) && $this->mapping[$t]['mapFieldNames'][$sqlPartArray[$k]['func']['field']]) {
03468                                 $sqlPartArray[$k]['func']['field'] = $this->mapping[$t]['mapFieldNames'][$sqlPartArray[$k]['func']['field']];
03469                             }
03470                             if ($this->mapping[$t]['mapTableName']) {
03471                                 $sqlPartArray[$k]['func']['table'] = $this->mapping[$t]['mapTableName'];
03472                             }
03473                             break;
03474                     }
03475                 } else {
03476                     // For the field, look for table mapping (generic):
03477                     $t = $sqlPartArray[$k]['table'] ? $sqlPartArray[$k]['table'] : $defaultTable;
03478                     $t = $this->getMappingKey($t);
03479 
03480                     // Mapping field name, if set:
03481                     if (is_array($this->mapping[$t]['mapFieldNames']) && isset($this->mapping[$t]['mapFieldNames'][$sqlPartArray[$k]['field']])) {
03482                         $sqlPartArray[$k]['field'] = $this->mapping[$t]['mapFieldNames'][$sqlPartArray[$k]['field']];
03483                     }
03484 
03485                     // Mapping field name in SQL-functions like MIN(), MAX() or SUM()
03486                     if ($this->mapping[$t]['mapFieldNames']) {
03487                         $fieldArray = explode('.', $sqlPartArray[$k]['func_content']);
03488                         if (count($fieldArray) == 1 && is_array($this->mapping[$t]['mapFieldNames']) && isset($this->mapping[$t]['mapFieldNames'][$fieldArray[0]])) {
03489                             $sqlPartArray[$k]['func_content.'][0]['func_content'] = $this->mapping[$t]['mapFieldNames'][$fieldArray[0]];
03490                             $sqlPartArray[$k]['func_content'] = $this->mapping[$t]['mapFieldNames'][$fieldArray[0]];
03491                         }
03492                         elseif (count($fieldArray) == 2) {
03493                             // Map the external table
03494                             $table = $fieldArray[0];
03495                             $tableKey = $this->getMappingKey($table);
03496                             if (isset($this->mapping[$tableKey]['mapTableName'])) {
03497                                 $table = $this->mapping[$tableKey]['mapTableName'];
03498                             }
03499                             // Map the field itself
03500                             $field = $fieldArray[1];
03501                             if (is_array($this->mapping[$tableKey]['mapFieldNames']) && isset($this->mapping[$tableKey]['mapFieldNames'][$fieldArray[1]])) {
03502                                 $field = $this->mapping[$tableKey]['mapFieldNames'][$fieldArray[1]];
03503                             }
03504                             $sqlPartArray[$k]['func_content.'][0]['func_content'] = $table . '.' . $field;
03505                             $sqlPartArray[$k]['func_content'] = $table . '.' . $field;
03506                         }
03507 
03508                         // Mapping flow-control statements
03509                         if (isset($sqlPartArray[$k]['flow-control'])) {
03510                             if (isset($sqlPartArray[$k]['flow-control']['type'])) {
03511                                 $temp = array($sqlPartArray[$k]['flow-control']);
03512                                 $this->map_sqlParts($temp, $t); // Call recursively!
03513                                 $sqlPartArray[$k]['flow-control'] = $temp[0];
03514                             }
03515                         }
03516                     }
03517 
03518                     // Do we have a function (e.g., CONCAT)
03519                     if (isset($v['value']['operator'])) {
03520                         foreach ($sqlPartArray[$k]['value']['args'] as $argK => $fieldDef) {
03521                             $tableKey = $this->getMappingKey($fieldDef['table']);
03522                             if (isset($this->mapping[$tableKey]['mapTableName'])) {
03523                                 $sqlPartArray[$k]['value']['args'][$argK]['table'] = $this->mapping[$tableKey]['mapTableName'];
03524                             }
03525                             if (is_array($this->mapping[$tableKey]['mapFieldNames']) && isset($this->mapping[$tableKey]['mapFieldNames'][$fieldDef['field']])) {
03526                                 $sqlPartArray[$k]['value']['args'][$argK]['field'] = $this->mapping[$tableKey]['mapFieldNames'][$fieldDef['field']];
03527                             }
03528                         }
03529                     }
03530 
03531                     // Do we have a subquery (WHERE parts only)?
03532                     if (isset($sqlPartArray[$k]['subquery'])) {
03533                         $this->map_subquery($sqlPartArray[$k]['subquery']);
03534                     }
03535 
03536                     // do we have a field name in the value?
03537                     // this is a very simplistic check, beware
03538                     if (!is_numeric($sqlPartArray[$k]['value'][0]) && !isset($sqlPartArray[$k]['value'][1])) {
03539                         $fieldArray = explode('.', $sqlPartArray[$k]['value'][0]);
03540                         if (count($fieldArray) == 1 && is_array($this->mapping[$t]['mapFieldNames']) && isset($this->mapping[$t]['mapFieldNames'][$fieldArray[0]])) {
03541                             $sqlPartArray[$k]['value'][0] = $this->mapping[$t]['mapFieldNames'][$fieldArray[0]];
03542                         } elseif (count($fieldArray) == 2) {
03543                             // Map the external table
03544                             $table = $fieldArray[0];
03545                             $tableKey = $this->getMappingKey($table);
03546                             if (isset($this->mapping[$tableKey]['mapTableName'])) {
03547                                 $table = $this->mapping[$tableKey]['mapTableName'];
03548                             }
03549                             // Map the field itself
03550                             $field = $fieldArray[1];
03551                             if (is_array($this->mapping[$tableKey]['mapFieldNames']) && isset($this->mapping[$tableKey]['mapFieldNames'][$fieldArray[1]])) {
03552                                 $field = $this->mapping[$tableKey]['mapFieldNames'][$fieldArray[1]];
03553                             }
03554                             $sqlPartArray[$k]['value'][0] = $table . '.' . $field;
03555                         }
03556                     }
03557 
03558                     // Map table?
03559                     $tableKey = $this->getMappingKey($sqlPartArray[$k]['table']);
03560                     if ($sqlPartArray[$k]['table'] && $this->mapping[$tableKey]['mapTableName']) {
03561                         $sqlPartArray[$k]['table'] = $this->mapping[$tableKey]['mapTableName'];
03562                     }
03563                 }
03564             }
03565         }
03566     }
03567 
03568     /**
03569      * Maps table and field names in a subquery.
03570      *
03571      * @param array $parsedQuery
03572      * @return void
03573      */
03574     protected function map_subquery(&$parsedQuery) {
03575         // Backup current mapping as it may be altered
03576         $backupMapping = $this->mapping;
03577 
03578         foreach ($parsedQuery['FROM'] as $k => $v) {
03579             $mappingKey = $v['table'];
03580             if ($v['as'] && is_array($this->mapping[$v['table']]['mapFieldNames'])) {
03581                 $mappingKey = $this->getFreeMappingKey($v['as']);
03582             } else {
03583                 // Should ensure that no alias is defined in the external query
03584                 // which would correspond to a real table name in the subquery
03585                 if ($this->getMappingKey($v['table']) !== $v['table']) {
03586                     $mappingKey = $this->getFreeMappingKey($v['table']);
03587                     // This is the only case when 'mapTableName' should be copied
03588                     $this->mapping[$mappingKey]['mapTableName'] =& $this->mapping[$v['table']]['mapTableName'];
03589                 }
03590             }
03591             if ($mappingKey !== $v['table']) {
03592                 $this->mapping[$mappingKey]['mapFieldNames'] =& $this->mapping[$v['table']]['mapFieldNames'];
03593             }
03594         }
03595 
03596         // Perform subquery's remapping
03597         $defaultTable = $parsedQuery['FROM'][0]['table'];
03598         $this->map_sqlParts($parsedQuery['SELECT'], $defaultTable);
03599         $this->map_sqlParts($parsedQuery['FROM'], $defaultTable);
03600         $this->map_sqlParts($parsedQuery['WHERE'], $defaultTable);
03601 
03602         // Restore the mapping
03603         $this->mapping = $backupMapping;
03604     }
03605 
03606     /**
03607      * Will do table/field mapping on a general tx_dbal_sqlengine-compliant SQL query
03608      * (May still not support all query types...)
03609      *
03610      * @param   array       Parsed QUERY as from tx_dbal_sqlengine::parseSQL(). NOTICE: Passed by reference!
03611      * @return  void
03612      * @see tx_dbal_sqlengine::parseSQL()
03613      */
03614     protected function map_genericQueryParsed(&$parsedQuery) {
03615 
03616         // Getting table - same for all:
03617         $table = $parsedQuery['TABLE'];
03618         if ($table) {
03619             // Do field mapping if needed:
03620             if ($tableArray = $this->map_needMapping($table)) {
03621 
03622                 // Table name:
03623                 if ($this->mapping[$table]['mapTableName']) {
03624                     $parsedQuery['TABLE'] = $this->mapping[$table]['mapTableName'];
03625                 }
03626 
03627                 // Based on type, do additional changes:
03628                 switch ($parsedQuery['type']) {
03629                     case 'ALTERTABLE':
03630 
03631                         // Changing field name:
03632                         $newFieldName = $this->mapping[$table]['mapFieldNames'][$parsedQuery['FIELD']];
03633                         if ($newFieldName) {
03634                             if ($parsedQuery['FIELD'] == $parsedQuery['newField']) {
03635                                 $parsedQuery['FIELD'] = $parsedQuery['newField'] = $newFieldName;
03636                             } else $parsedQuery['FIELD'] = $newFieldName;
03637                         }
03638 
03639                         // Changing key field names:
03640                         if (is_array($parsedQuery['fields'])) {
03641                             $this->map_fieldNamesInArray($table, $parsedQuery['fields']);
03642                         }
03643                         break;
03644                     case 'CREATETABLE':
03645                         // Remapping fields:
03646                         if (is_array($parsedQuery['FIELDS'])) {
03647                             $newFieldsArray = array();
03648                             foreach ($parsedQuery['FIELDS'] as $fN => $fInfo) {
03649                                 if ($this->mapping[$table]['mapFieldNames'][$fN]) {
03650                                     $fN = $this->mapping[$table]['mapFieldNames'][$fN];
03651                                 }
03652                                 $newFieldsArray[$fN] = $fInfo;
03653                             }
03654                             $parsedQuery['FIELDS'] = $newFieldsArray;
03655                         }
03656 
03657                         // Remapping keys:
03658                         if (is_array($parsedQuery['KEYS'])) {
03659                             foreach ($parsedQuery['KEYS'] as $kN => $kInfo) {
03660                                 $this->map_fieldNamesInArray($table, $parsedQuery['KEYS'][$kN]);
03661                             }
03662                         }
03663                         break;
03664 
03665                     /// ... and here support for all other query types should be!
03666 
03667                 }
03668             }
03669         } else die('ERROR, mapping: No table found in parsed Query array...');
03670     }
03671 
03672     /**
03673      * Re-mapping field names in array
03674      *
03675      * @param   string      (TYPO3) Table name for fields.
03676      * @param   array       Array of fieldnames to remap. Notice: Passed by reference!
03677      * @return  void
03678      */
03679     protected function map_fieldNamesInArray($table, &$fieldArray) {
03680         if (is_array($this->mapping[$table]['mapFieldNames'])) {
03681             foreach ($fieldArray as $k => $v) {
03682                 if ($this->mapping[$table]['mapFieldNames'][$v]) {
03683                     $fieldArray[$k] = $this->mapping[$table]['mapFieldNames'][$v];
03684                 }
03685             }
03686         }
03687     }
03688 
03689 
03690     /**************************************
03691      *
03692      * Debugging
03693      *
03694      **************************************/
03695 
03696     /**
03697      * Debug handler for query execution
03698      *
03699      * @param   string      Function name from which this function is called.
03700      * @param   string      Execution time in ms of the query
03701      * @param   array       In-data of various kinds.
03702      * @return  void
03703      * @access private
03704      */
03705     public function debugHandler($function, $execTime, $inData) {
03706         // we don't want to log our own log/debug SQL
03707         $script = substr(PATH_thisScript, strlen(PATH_site));
03708 
03709         if (substr($script, -strlen('dbal/mod1/index.php')) != 'dbal/mod1/index.php' && !strstr($inData['args'][0], 'tx_dbal_debuglog')) {
03710             $data = array();
03711             $errorFlag = 0;
03712             $joinTable = '';
03713 
03714             if ($this->sql_error()) {
03715                 $data['sqlError'] = $this->sql_error();
03716                 $errorFlag |= 1;
03717             }
03718 
03719             // if lastQuery is empty (for whatever reason) at least log inData.args
03720             if (empty($this->lastQuery)) {
03721                 $query = implode(' ', $inData['args']);
03722             } else {
03723                 $query = $this->lastQuery;
03724             }
03725 
03726             if ($this->conf['debugOptions']['numberRows']) {
03727                 switch ($function) {
03728                     case 'exec_INSERTquery':
03729                     case 'exec_UPDATEquery':
03730                     case 'exec_DELETEquery':
03731                         $data['numberRows'] = $this->sql_affected_rows();
03732                         break;
03733                     case 'exec_SELECTquery':
03734                         $data['numberRows'] = $inData['numberRows'];
03735                         break;
03736                 }
03737             }
03738 
03739             if ($this->conf['debugOptions']['backtrace']) {
03740                 $backtrace = debug_backtrace();
03741                 unset($backtrace[0]); // skip this very method :)
03742                 $data['backtrace'] = array_slice($backtrace, 0, $this->conf['debugOptions']['backtrace']);
03743             }
03744 
03745             switch ($function) {
03746                 case 'exec_INSERTquery':
03747                 case 'exec_UPDATEquery':
03748                 case 'exec_DELETEquery':
03749                     $this->debug_log($query, $execTime, $data, $joinTable, $errorFlag, $script);
03750                     break;
03751 
03752                 case 'exec_SELECTquery':
03753                     // Get explain data:
03754                     if ($this->conf['debugOptions']['EXPLAIN'] && t3lib_div::inList('adodb,native', $inData['handlerType'])) {
03755                         $data['EXPLAIN'] = $this->debug_explain($this->lastQuery);
03756                     }
03757 
03758                     // Check parsing of Query:
03759                     if ($this->conf['debugOptions']['parseQuery']) {
03760                         $parseResults = array();
03761                         $parseResults['SELECT'] = $this->SQLparser->debug_parseSQLpart('SELECT', $inData['args'][1]);
03762                         $parseResults['FROM'] = $this->SQLparser->debug_parseSQLpart('FROM', $inData['args'][0]);
03763                         $parseResults['WHERE'] = $this->SQLparser->debug_parseSQLpart('WHERE', $inData['args'][2]);
03764                         $parseResults['GROUPBY'] = $this->SQLparser->debug_parseSQLpart('SELECT', $inData['args'][3]); // Using select field list syntax
03765                         $parseResults['ORDERBY'] = $this->SQLparser->debug_parseSQLpart('SELECT', $inData['args'][4]); // Using select field list syntax
03766 
03767                         foreach ($parseResults as $k => $v) {
03768                             if (!strlen($parseResults[$k])) unset($parseResults[$k]);
03769                         }
03770                         if (count($parseResults)) {
03771                             $data['parseError'] = $parseResults;
03772                             $errorFlag |= 2;
03773                         }
03774                     }
03775 
03776                     // Checking joinTables:
03777                     if ($this->conf['debugOptions']['joinTables']) {
03778                         if (count(explode(',', $inData['ORIG_from_table'])) > 1) {
03779                             $joinTable = $inData['args'][0];
03780                         }
03781                     }
03782 
03783                     // Logging it:
03784                     $this->debug_log($query, $execTime, $data, $joinTable, $errorFlag, $script);
03785                     if (!empty($inData['args'][2]))
03786                         $this->debug_WHERE($inData['args'][0], $inData['args'][2], $script);
03787                     break;
03788             }
03789         }
03790     }
03791 
03792     /**
03793      * Logs the where clause for debugging purposes.
03794      *
03795      * @param string $table Table name(s) the query was targeted at
03796      * @param string $where The WHERE clause to be logged
03797      * @param string $script    The script calling the logging
03798      * @return void
03799      */
03800     public function debug_WHERE($table, $where, $script = '') {
03801         $insertArray = array(
03802             'tstamp' => $GLOBALS['EXEC_TIME'],
03803             'beuser_id' => intval($GLOBALS['BE_USER']->user['uid']),
03804             'script' => $script,
03805             'tablename' => $table,
03806             'whereclause' => $where
03807         );
03808 
03809         $this->exec_INSERTquery('tx_dbal_debuglog_where', $insertArray);
03810     }
03811 
03812     /**
03813      * Inserts row in the log table
03814      *
03815      * @param   string      The current query
03816      * @param   integer     Execution time of query in milliseconds
03817      * @param   array       Data to be stored serialized.
03818      * @param   string      Join string if there IS a join.
03819      * @param   integer     Error status.
03820      * @param string $script    The script calling the logging
03821      * @return  void
03822      */
03823     public function debug_log($query, $ms, $data, $join, $errorFlag, $script = '') {
03824         if (is_array($query)) {
03825             $queryToLog = $query[0] . ' --  ';
03826             if (count($query[1])) {
03827                 $queryToLog .= count($query[1]) . ' BLOB FIELDS: ' . implode(', ', array_keys($query[1]));
03828             }
03829             if (count($query[2])) {
03830                 $queryToLog .= count($query[2]) . ' CLOB FIELDS: ' . implode(', ', array_keys($query[2]));
03831             }
03832         } else {
03833             $queryToLog = $query;
03834         }
03835         $insertArray = array(
03836             'tstamp' => $GLOBALS['EXEC_TIME'],
03837             'beuser_id' => intval($GLOBALS['BE_USER']->user['uid']),
03838             'script' => $script,
03839             'exec_time' => $ms,
03840             'table_join' => $join,
03841             'serdata' => serialize($data),
03842             'query' => $queryToLog,
03843             'errorFlag' => $errorFlag
03844         );
03845 
03846         $this->exec_INSERTquery('tx_dbal_debuglog', $insertArray);
03847     }
03848 
03849     /**
03850      * Perform EXPLAIN query on DEFAULT handler!
03851      *
03852      * @param   string      SELECT Query
03853      * @return  array       The Explain result rows in an array
03854      * @todo    Not supporting other than the default handler? And what about DBMS of other kinds than MySQL - support for EXPLAIN?
03855      */
03856     public function debug_explain($query) {
03857         $output = array();
03858         $hType = (string) $this->handlerCfg[$this->lastHandlerKey]['type'];
03859         switch ($hType) {
03860             case 'native':
03861                 $res = $this->sql_query('EXPLAIN ' . $query);
03862                 while ($row = $this->sql_fetch_assoc($res)) {
03863                     $output[] = $row;
03864                 }
03865                 break;
03866             case 'adodb':
03867                 switch ($this->handlerCfg['_DEFAULT']['config']['driver']) {
03868                     case 'oci8':
03869                         $res = $this->sql_query('EXPLAIN PLAN ' . $query);
03870                         $output[] = 'EXPLAIN PLAN data logged to default PLAN_TABLE';
03871                         break;
03872                     default:
03873                         $res = $this->sql_query('EXPLAIN ' . $query);
03874                         while ($row = $this->sql_fetch_assoc($res)) {
03875                             $output[] = $row;
03876                         }
03877                         break;
03878                 }
03879                 break;
03880         }
03881 
03882         return $output;
03883     }
03884 }
03885 
03886 
03887 if (defined('TYPO3_MODE') && isset($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLASS']['ext/dbal/class.ux_t3lib_db.php'])) {
03888     include_once($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLASS']['ext/dbal/class.ux_t3lib_db.php']);
03889 }
03890 
03891 ?>