class.ux_t3lib_db.php

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

Generated on Sat Mar 6 04:17:15 2010 for TYPO3 API by  doxygen 1.4.7