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

Generated on Sat Jul 4 04:15:52 2009 for TYPO3 API by  doxygen 1.5.8