ChangeLog
[Packages/TYPO3.CMS.git] / typo3 / sysext / dbal / class.ux_t3lib_db.php
1 <?php
2 /***************************************************************
3 * Copyright notice
4 *
5 * (c) 2004-2006 Kasper Skaarhoj (kasperYYYY@typo3.com)
6 * All rights reserved
7 *
8 * This script is part of the TYPO3 project. The TYPO3 project is
9 * free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * The GNU General Public License can be found at
15 * http://www.gnu.org/copyleft/gpl.html.
16 * A copy is found in the textfile GPL.txt and important notices to the license
17 * from the author is found in LICENSE.txt distributed with these scripts.
18 *
19 *
20 * This script is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
24 *
25 * This copyright notice MUST APPEAR in all copies of the script!
26 ***************************************************************/
27 /**
28 * Contains a database abstraction layer class for TYPO3
29 *
30 * $Id$
31 *
32 * @author Kasper Skaarhoj <kasper@typo3.com>
33 * @author Karsten Dambekalns <k.dambekalns@fishfarm.de>
34 */
35 /**
36 * [CLASS/FUNCTION INDEX of SCRIPT]
37 *
38 *
39 *
40 * 123: class ux_t3lib_DB extends t3lib_DB
41 * 169: function ux_t3lib_DB()
42 * 184: function initInternalVariables()
43 *
44 * SECTION: Query Building (Overriding parent methods)
45 * 217: function exec_INSERTquery($table,$fields_values)
46 * 275: function exec_UPDATEquery($table,$where,$fields_values)
47 * 334: function exec_DELETEquery($table,$where)
48 * 387: function exec_SELECTquery($select_fields,$from_table,$where_clause,$groupBy='',$orderBy='',$limit='')
49 *
50 * SECTION: Creates an INSERT SQL-statement for $table from the array with field/value pairs $fields_values.
51 * 533: function SELECTquery($select_fields,$from_table,$where_clause,$groupBy='',$orderBy='',$limit='')
52 * 556: function quoteSelectFields(&$select_fields)
53 * 573: function quoteFromTables(&$from_table)
54 * 595: function quoteWhereClause(&$where_clause)
55 * 620: function quoteGroupBy(&$groupBy)
56 * 637: function quoteOrderBy(&$orderBy)
57 *
58 * SECTION: Various helper functions
59 * 663: function quoteStr($str, $table)
60 *
61 * SECTION: SQL wrapper functions (Overriding parent methods)
62 * 707: function sql_error()
63 * 734: function sql_num_rows(&$res)
64 * 760: function sql_fetch_assoc(&$res)
65 * 808: function sql_fetch_row(&$res)
66 * 842: function sql_free_result(&$res)
67 * 868: function sql_insert_id()
68 * 893: function sql_affected_rows()
69 * 919: function sql_data_seek(&$res,$seek)
70 * 946: function sql_field_type(&$res,$pointer)
71 *
72 * SECTION: Legacy functions, bound to _DEFAULT handler. (Overriding parent methods)
73 * 987: function sql($db,$query)
74 * 999: function sql_query($query)
75 * 1035: function sql_pconnect($TYPO3_db_host, $TYPO3_db_username, $TYPO3_db_password)
76 * 1055: function sql_select_db($TYPO3_db)
77 *
78 * SECTION: SQL admin functions
79 * 1086: function admin_get_tables()
80 * 1149: function admin_get_fields($tableName)
81 * 1210: function admin_get_keys($tableName)
82 * 1270: function admin_query($query)
83 *
84 * SECTION: Handler management
85 * 1333: function handler_getFromTableList($tableList)
86 * 1379: function handler_init($handlerKey)
87 *
88 * SECTION: Table/Field mapping
89 * 1488: function map_needMapping($tableList,$fieldMappingOnly=FALSE)
90 * 1524: function map_assocArray($input,$tables,$rev=FALSE)
91 * 1573: function map_remapSELECTQueryParts(&$select_fields,&$from_table,&$where_clause,&$groupBy,&$orderBy)
92 * 1615: function map_sqlParts(&$sqlPartArray, $defaultTable)
93 * 1650: function map_genericQueryParsed(&$parsedQuery)
94 * 1717: function map_fieldNamesInArray($table,&$fieldArray)
95 *
96 * SECTION: Debugging
97 * 1758: function debugHandler($function,$execTime,$inData)
98 * 1823: function debug_log($query,$ms,$data,$join,$errorFlag)
99 * 1849: function debug_explain($query)
100 *
101 * TOTAL FUNCTIONS: 41
102 * (This index is automatically created/updated by the extension "extdeveval")
103 *
104 */
105
106
107
108
109
110
111
112
113
114
115 require_once(PATH_t3lib.'class.t3lib_sqlengine.php');
116 require_once(PATH_t3lib.'class.t3lib_install.php');
117
118 /**
119 * TYPO3 database abstraction layer
120 *
121 * @author Kasper Skaarhoj <kasper@typo3.com>
122 * @author Karsten Dambekalns <k.dambekalns@fishfarm.de>
123 * @package TYPO3
124 * @subpackage tx_dbal
125 */
126 class ux_t3lib_DB extends t3lib_DB {
127
128 // Internal, static:
129 var $printErrors = false; // Enable output of SQL errors after query executions. Set through TYPO3_CONF_VARS, see init()
130 var $debug = false; // Enable debug mode. Set through TYPO3_CONF_VARS, see init()
131 var $conf = array(); // Configuration array, copied from TYPO3_CONF_VARS in constructor.
132
133 var $mapping = array(); // See manual.
134 var $table2handlerKeys = array(); // See manual.
135 var $handlerCfg = array ( // See manual.
136 '_DEFAULT' => array (
137 'type' => 'native',
138 'config' => array(
139 'username' => '', // Set by default (overridden)
140 'password' => '', // Set by default (overridden)
141 'host' => '', // Set by default (overridden)
142 'database' => '', // Set by default (overridden)
143 'driver' => '', // ONLY "adodb" type; eg. "mysql"
144 'sequenceStart' => 1 // ONLY "adodb", first number in sequences/serials/...
145 )
146 ),
147 );
148
149
150 // Internal, dynamic:
151 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.
152 var $lastHandlerKey = ''; // Storage of the handler key of last ( SELECT) query - used for subsequent fetch-row calls etc.
153 var $lastQuery = ''; // Storage of last SELECT query
154 var $lastParsedAndMappedQueryArray = array(); // Query array, the last one parsed
155
156 var $resourceIdToTableNameMap = array(); // Mapping of resource ids to table names.
157
158 // Internal, caching:
159 var $cache_handlerKeyFromTableList = array(); // Caching handlerKeys for table lists
160 var $cache_mappingFromTableList = array(); // Caching mapping information for table lists
161 var $cache_autoIncFields = array(); // parsed SQL from standard DB dump file
162 var $cache_fieldType = array(); // field types for tables/fields
163 var $cache_primaryKeys = array(); // primary keys
164
165
166
167 /**
168 * Constructor.
169 * Creates SQL parser object and imports configuration from $TYPO3_CONF_VARS['EXTCONF']['dbal']
170 *
171 * @return void
172 */
173 function ux_t3lib_DB() {
174
175 // Set SQL parser object for internal use:
176 $this->SQLparser = t3lib_div::makeInstance('t3lib_sqlengine');
177 $this->Installer = t3lib_div::makeInstance('t3lib_install');
178
179 // Set internal variables with configuration:
180 $this->conf = $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['dbal'];
181 $this->initInternalVariables();
182 }
183
184 /**
185 * Setting internal variables from $this->conf
186 *
187 * @return void
188 */
189 function initInternalVariables() {
190
191 // Set outside configuration:
192 if (isset($this->conf['mapping'])) $this->mapping = $this->conf['mapping'];
193 if (isset($this->conf['table2handlerKeys'])) $this->table2handlerKeys = $this->conf['table2handlerKeys'];
194 if (isset($this->conf['handlerCfg'])) $this->handlerCfg = $this->conf['handlerCfg'];
195
196 $this->cacheFieldInfo();
197 // Debugging settings:
198 $this->printErrors = $this->conf['debugOptions']['printErrors'] ? TRUE : FALSE;
199 $this->debug = $this->conf['debugOptions']['enabled'] ? TRUE : FALSE;
200 }
201
202 function clearCachedFieldInfo() {
203 if(file_exists(PATH_typo3conf.'temp_fieldInfo.php'))
204 unlink(PATH_typo3conf.'temp_fieldInfo.php');
205 }
206
207 function cacheFieldInfo() {
208 global $TYPO3_LOADED_EXT;
209 $extSQL = '';
210 $parsedExtSQL = array();
211
212 // try to fetch cached file first
213 // file is removed when admin_query() is called
214 if(file_exists(PATH_typo3conf.'temp_fieldInfo.php')) {
215 $fdata = unserialize(t3lib_div::getUrl(PATH_typo3conf.'temp_fieldInfo.php'));
216 $this->cache_autoIncFields = $fdata['incFields'];
217 $this->cache_fieldType = $fdata['fieldTypes'];
218 $this->cache_primaryKeys = $fdata['primaryKeys'];
219 }
220 else {
221 // handle stddb.sql, parse and analyze
222 $extSQL = t3lib_div::getUrl(PATH_site.'t3lib/stddb/tables.sql');
223 $parsedExtSQL = $this->Installer->getFieldDefinitions_sqlContent($extSQL);
224 $this->analyzeFields($parsedExtSQL);
225
226 // loop over all installed extensions
227 foreach($TYPO3_LOADED_EXT as $ext => $v) {
228 if(!is_array($v) || !isset($v['ext_tables.sql']))
229 continue;
230
231 // fetch db dump (if any) and parse it, then analyze
232 $extSQL = t3lib_div::getUrl($v['ext_tables.sql']);
233 $parsedExtSQL = $this->Installer->getFieldDefinitions_sqlContent($extSQL);
234 $this->analyzeFields($parsedExtSQL);
235 }
236
237 $cachedFieldInfo = array('incFields' => $this->cache_autoIncFields, 'fieldTypes' => $this->cache_fieldType, 'primaryKeys' => $this->cache_primaryKeys);
238 $cachedFieldInfo = serialize($this->mapCachedFieldInfo($cachedFieldInfo));
239
240 // write serialized content to file
241 t3lib_div::writeFile(PATH_typo3conf."temp_fieldInfo.php", $cachedFieldInfo);
242
243 if (strcmp(t3lib_div::getUrl(PATH_typo3conf."temp_fieldInfo.php"), $cachedFieldInfo)) {
244 die('typo3temp/temp_incfields.php was NOT updated properly (written content didn\'t match file content) - maybe write access problem?');
245 }
246 }
247 }
248
249 /**
250 * Analyzes fields and adds the extracted information to the field type, auto increment and primary key info caches.
251 *
252 * @param array $parsedExtSQL The output produced by t3lib_install::getFieldDefinitions_sqlContent()
253 * @return void
254 * @see t3lib_install::getFieldDefinitions_sqlContent()
255 */
256 function analyzeFields($parsedExtSQL) {
257 foreach($parsedExtSQL as $table => $tdef) {
258 foreach($tdef['fields'] as $field => $fdef) {
259 $fdef = $this->SQLparser->parseFieldDef($fdef);
260 $this->cache_fieldType[$table][$field]['type'] = $fdef['fieldType'];
261 $this->cache_fieldType[$table][$field]['metaType'] = $this->MySQLMetaType($fdef['fieldType']);
262 $this->cache_fieldType[$table][$field]['notnull'] = (isset($fdef['featureIndex']['NOTNULL']) && !$this->SQLparser->checkEmptyDefaultValue($fdef['featureIndex'])) ? 1 : 0;
263 if(isset($fdef['featureIndex']['AUTO_INCREMENT'])) {
264 $this->cache_autoIncFields[$table] = $field;
265 }
266 if(isset($tdef['keys']['PRIMARY'])) {
267 $this->cache_primaryKeys[$table] = substr($tdef['keys']['PRIMARY'], 13, -1);
268 }
269 }
270 }
271 }
272
273 /**
274 * This function builds all definitions for mapped tables and fields
275 * @see cacheFieldInfo()
276 */
277 function mapCachedFieldInfo($fieldInfo){
278 global $TYPO3_CONF_VARS;
279
280 if(is_array($TYPO3_CONF_VARS['EXTCONF']['dbal']['mapping'])) {
281 foreach($TYPO3_CONF_VARS['EXTCONF']['dbal']['mapping'] as $mappedTable => $mappedConf){
282 if(array_key_exists($mappedTable, $fieldInfo['incFields'])) {
283 $mappedTableAlias = $mappedConf['mapTableName'];
284 $fieldInfo['incFields'][$mappedTableAlias] = isset($mappedConf['mapFieldNames'][$fieldInfo['incFields'][$mappedTable]]) ? $mappedConf['mapFieldNames'][$fieldInfo['incFields'][$mappedTable]] : $fieldInfo['incFields'][$mappedTable];
285 }
286
287 if(array_key_exists($mappedTable, $fieldInfo['fieldTypes'])) {
288 foreach($fieldInfo['fieldTypes'][$mappedTable] as $field => $fieldConf){
289 $tempMappedFieldConf[$mappedConf['mapFieldNames'][$field]] = $fieldConf;
290 }
291
292 $fieldInfo['fieldTypes'][$mappedConf['mapTableName']] = $tempMappedFieldConf;
293 }
294
295 if(array_key_exists($mappedTable, $fieldInfo['primaryKeys'])) {
296 $mappedTableAlias = $mappedConf['mapTableName'];
297 $fieldInfo['primaryKeys'][$mappedTableAlias] = isset($mappedConf['mapFieldNames'][$fieldInfo['primaryKeys'][$mappedTable]]) ? $mappedConf['mapFieldNames'][$fieldInfo['primaryKeys'][$mappedTable]] : $fieldInfo['primaryKeys'][$mappedTable];
298 }
299
300 }
301 }
302
303 return $fieldInfo;
304 }
305
306
307 /************************************
308 *
309 * Query Building (Overriding parent methods)
310 * These functions are extending counterparts in the parent class.
311 *
312 **************************************/
313
314 /* From the ADOdb documentation, this is what we do (_Execute for SELECT, _query for the other actions)
315
316 Execute() is the default way to run queries. You can use the low-level functions _Execute() and _query() to reduce query overhead.
317 Both these functions share the same parameters as Execute().
318
319 If you do not have any bind parameters or your database supports binding (without emulation), then you can call _Execute() directly.
320 Calling this function bypasses bind emulation. Debugging is still supported in _Execute().
321
322 If you do not require debugging facilities nor emulated binding, and do not require a recordset to be returned, then you can call _query.
323 This is great for inserts, updates and deletes. Calling this function bypasses emulated binding, debugging, and recordset handling. Either
324 the resultid, true or false are returned by _query().
325 */
326
327 /**
328 * Inserts a record for $table from the array with field/value pairs $fields_values.
329 *
330 * @param string Table name
331 * @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.
332 * @param mixed List/array of keys NOT to quote (eg. SQL functions)
333 * @return mixed Result from handler, usually TRUE when success and FALSE on failure
334 */
335 function exec_INSERTquery($table,$fields_values,$no_quote_fields='') {
336
337 if ($this->debug) $pt = t3lib_div::milliseconds();
338
339 // Do field mapping if needed:
340 $ORIG_tableName = $table;
341 if ($tableArray = $this->map_needMapping($table)) {
342
343 // Field mapping of array:
344 $fields_values = $this->map_assocArray($fields_values,$tableArray);
345
346 // Table name:
347 if ($this->mapping[$table]['mapTableName']) {
348 $table = $this->mapping[$table]['mapTableName'];
349 }
350 }
351 // Select API:
352 $this->lastHandlerKey = $this->handler_getFromTableList($ORIG_tableName);
353 switch((string)$this->handlerCfg[$this->lastHandlerKey]['type']) {
354 case 'native':
355 $this->lastQuery = $this->INSERTquery($table,$fields_values,$no_quote_fields);
356 if(is_string($this->lastQuery)) {
357 $sqlResult = mysql_query($this->lastQuery, $this->handlerInstance[$this->lastHandlerKey]['link']);
358 }
359 else {
360 $sqlResult = mysql_query($this->lastQuery[0], $this->handlerInstance[$this->lastHandlerKey]['link']);
361 foreach($this->lastQuery[1] as $field => $content) {
362 mysql_query('UPDATE '.$this->quoteFromTables($table).' SET '.$this->quoteFromTables($field).'='.$this->fullQuoteStr($content,$table).' WHERE '.$this->quoteWhereClause($where), $this->handlerInstance[$this->lastHandlerKey]['link']);
363 }
364 }
365 break;
366 case 'adodb':
367 // auto generate ID for auto_increment fields if not present (static import needs this!)
368 // should we check the table name here (static_*)?
369 if(isset($this->cache_autoIncFields[$table])) {
370 if(isset($fields_values[$this->cache_autoIncFields[$table]])) {
371 $new_id = $fields_values[$this->cache_autoIncFields[$table]];
372 if($table !== 'tx_dbal_debuglog') {
373 $this->handlerInstance[$this->lastHandlerKey]->last_insert_id = $new_id;
374 }
375 } else {
376 $new_id = $this->handlerInstance[$this->lastHandlerKey]->GenID($table.'_'.$this->cache_autoIncFields[$table], $this->handlerInstance[$this->lastHandlerKey]->sequenceStart);
377 $fields_values[$this->cache_autoIncFields[$table]] = $new_id;
378 if($table !== 'tx_dbal_debuglog') {
379 $this->handlerInstance[$this->lastHandlerKey]->last_insert_id = $new_id;
380 }
381 }
382 }
383
384 $this->lastQuery = $this->INSERTquery($table,$fields_values,$no_quote_fields);
385 if(is_string($this->lastQuery)) {
386 $sqlResult = $this->handlerInstance[$this->lastHandlerKey]->_query($this->lastQuery,false);
387 } else {
388 $this->handlerInstance[$this->lastHandlerKey]->StartTrans();
389 if(strlen($this->lastQuery[0]))
390 $sqlResult = $this->handlerInstance[$this->lastHandlerKey]->_query($this->lastQuery[0],false);
391 foreach($this->lastQuery[1] as $field => $content) {
392 if(empty($content)) continue;
393
394 if(isset($this->cache_autoIncFields[$table]) && isset($new_id)) {
395 $this->handlerInstance[$this->lastHandlerKey]->UpdateBlob($this->quoteFromTables($table),$field,$content,$this->quoteWhereClause($this->cache_autoIncFields[$table].'='.$new_id));
396 } elseif(isset($this->cache_primaryKeys[$table])) {
397 $pks = explode(',', $this->cache_primaryKeys[$table]);
398 foreach ($pks as $pk) {
399 if(isset($fields_values[$pk]))
400 $where .= $pk.'='.$this->fullQuoteStr($fields_values[$pk], $table).' AND ';
401 }
402 $where = $this->quoteWhereClause($where.'1=1');
403 $this->handlerInstance[$this->lastHandlerKey]->UpdateBlob($this->quoteFromTables($table),$field,$content,$where);
404 } else {
405 $this->handlerInstance[$this->lastHandlerKey]->CompleteTrans(false);
406 die('Could not update BLOB >>>> no WHERE clause found!'); // should never ever happen
407 }
408 }
409 $this->handlerInstance[$this->lastHandlerKey]->CompleteTrans();
410 }
411 break;
412 case 'userdefined':
413 $sqlResult = $this->handlerInstance[$this->lastHandlerKey]->exec_INSERTquery($table,$fields_values,$no_quote_fields);
414 break;
415 }
416
417 if ($this->printErrors && $this->sql_error()) {
418 debug(array($this->lastQuery, $this->sql_error()));
419 }
420
421 if ($this->debug) {
422 $this->debugHandler(
423 'exec_INSERTquery',
424 t3lib_div::milliseconds()-$pt,
425 array(
426 'handlerType' => $hType,
427 'args' => array($table,$fields_values),
428 'ORIG_tablename' => $ORIG_tableName
429 )
430 );
431 }
432 // Return output:
433 return $sqlResult;
434 }
435
436 /**
437 * Updates a record from $table
438 *
439 * @param string Database tablename
440 * @param string WHERE clause, eg. "uid=1". NOTICE: You must escape values in this argument with $this->fullQuoteStr() yourself!
441 * @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.
442 * @param mixed List/array of keys NOT to quote (eg. SQL functions)
443 * @return mixed Result from handler, usually TRUE when success and FALSE on failure
444 */
445 function exec_UPDATEquery($table,$where,$fields_values,$no_quote_fields='') {
446
447 if ($this->debug) $pt = t3lib_div::milliseconds();
448
449 // Do table/field mapping:
450 $ORIG_tableName = $table;
451 if ($tableArray = $this->map_needMapping($table)) {
452
453 // Field mapping of array:
454 $fields_values = $this->map_assocArray($fields_values,$tableArray);
455
456 // Where clause table and field mapping:
457 $whereParts = $this->SQLparser->parseWhereClause($where);
458 $this->map_sqlParts($whereParts,$tableArray[0]['table']);
459 $where = $this->SQLparser->compileWhereClause($whereParts);
460
461 // Table name:
462 if ($this->mapping[$table]['mapTableName']) {
463 $table = $this->mapping[$table]['mapTableName'];
464 }
465 }
466
467 // Select API
468 $this->lastHandlerKey = $this->handler_getFromTableList($ORIG_tableName);
469 switch((string)$this->handlerCfg[$this->lastHandlerKey]['type']) {
470 case 'native':
471 $this->lastQuery = $this->UPDATEquery($table,$where,$fields_values,$no_quote_fields);
472 if(is_string($this->lastQuery)) {
473 $sqlResult = mysql_query($this->lastQuery, $this->handlerInstance[$this->lastHandlerKey]['link']);
474 }
475 else {
476 $sqlResult = mysql_query($this->lastQuery[0], $this->handlerInstance[$this->lastHandlerKey]['link']);
477 foreach($this->lastQuery[1] as $field => $content) {
478 mysql_query('UPDATE '.$this->quoteFromTables($table).' SET '.$this->quoteFromTables($field).'='.$this->fullQuoteStr($content,$table).' WHERE '.$this->quoteWhereClause($where), $this->handlerInstance[$this->lastHandlerKey]['link']);
479 }
480 }
481 break;
482 case 'adodb':
483 $this->lastQuery = $this->UPDATEquery($table,$where,$fields_values,$no_quote_fields);
484 if(is_string($this->lastQuery)) {
485 $sqlResult = $this->handlerInstance[$this->lastHandlerKey]->_query($this->lastQuery,false);
486 } else {
487 $this->handlerInstance[$this->lastHandlerKey]->StartTrans();
488 if(strlen($this->lastQuery[0]))
489 $sqlResult = $this->handlerInstance[$this->lastHandlerKey]->_query($this->lastQuery[0],false);
490 foreach($this->lastQuery[1] as $field => $content) {
491 $this->handlerInstance[$this->lastHandlerKey]->UpdateBlob($this->quoteFromTables($table),$field,$content,$this->quoteWhereClause($where));
492 }
493 $this->handlerInstance[$this->lastHandlerKey]->CompleteTrans();
494 }
495 break;
496 case 'userdefined':
497 $sqlResult = $this->handlerInstance[$this->lastHandlerKey]->exec_UPDATEquery($table,$where,$fields_values,$no_quote_fields);
498 break;
499 }
500
501 if ($this->printErrors && $this->sql_error()) {
502 debug(array($this->lastQuery, $this->sql_error()));
503 }
504
505 if ($this->debug) {
506 $this->debugHandler(
507 'exec_UPDATEquery',
508 t3lib_div::milliseconds()-$pt,
509 array(
510 'handlerType' => $hType,
511 'args' => array($table,$where, $fields_values),
512 'ORIG_from_table' => $ORIG_tableName
513 )
514 );
515 }
516
517 // Return result:
518 return $sqlResult;
519 }
520
521 /**
522 * Deletes records from table
523 *
524 * @param string Database tablename
525 * @param string WHERE clause, eg. "uid=1". NOTICE: You must escape values in this argument with $this->fullQuoteStr() yourself!
526 * @return mixed Result from handler
527 */
528 function exec_DELETEquery($table,$where) {
529
530 if ($this->debug) $pt = t3lib_div::milliseconds();
531
532 // Do table/field mapping:
533 $ORIG_tableName = $table;
534 if ($tableArray = $this->map_needMapping($table)) {
535
536 // Where clause:
537 $whereParts = $this->SQLparser->parseWhereClause($where);
538 $this->map_sqlParts($whereParts,$tableArray[0]['table']);
539 $where = $this->SQLparser->compileWhereClause($whereParts);
540
541 // Table name:
542 if ($this->mapping[$table]['mapTableName']) {
543 $table = $this->mapping[$table]['mapTableName'];
544 }
545 }
546
547 // Select API
548 $this->lastHandlerKey = $this->handler_getFromTableList($ORIG_tableName);
549 switch((string)$this->handlerCfg[$this->lastHandlerKey]['type']) {
550 case 'native':
551 $this->lastQuery = $this->DELETEquery($table,$where);
552 $sqlResult = mysql_query($this->lastQuery, $this->handlerInstance[$this->lastHandlerKey]['link']);
553 break;
554 case 'adodb':
555 $this->lastQuery = $this->DELETEquery($table,$where);
556 $sqlResult = $this->handlerInstance[$this->lastHandlerKey]->_query($this->lastQuery,false);
557 break;
558 case 'userdefined':
559 $sqlResult = $this->handlerInstance[$this->lastHandlerKey]->exec_DELETEquery($table,$where);
560 break;
561 }
562
563 if ($this->printErrors && $this->sql_error()) {
564 debug(array($this->lastQuery, $this->sql_error()));
565 }
566
567 if ($this->debug) {
568 $this->debugHandler(
569 'exec_DELETEquery',
570 t3lib_div::milliseconds()-$pt,
571 array(
572 'handlerType' => $hType,
573 'args' => array($table,$where),
574 'ORIG_from_table' => $ORIG_tableName
575 )
576 );
577 }
578
579 // Return result:
580 return $sqlResult;
581 }
582
583 /**
584 * Selects records from Data Source
585 *
586 * @param string $select_fields List of fields to select from the table. This is what comes right after "SELECT ...". Required value.
587 * @param string $from_table Table(s) from which to select. This is what comes right after "FROM ...". Required value.
588 * @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!
589 * @param string $groupBy Optional GROUP BY field(s), if none, supply blank string.
590 * @param string $orderBy Optional ORDER BY field(s), if none, supply blank string.
591 * @param string $limit Optional LIMIT value ([begin,]max), if none, supply blank string.
592 * @return mixed Result from handler. Typically object from DBAL layers.
593 */
594 function exec_SELECTquery($select_fields,$from_table,$where_clause,$groupBy='',$orderBy='',$limit='') {
595
596 if ($this->debug) $pt = t3lib_div::milliseconds();
597
598 // Map table / field names if needed:
599 $ORIG_tableName = $from_table; // Saving table names in $ORIG_from_table since $from_table is transformed beneath:
600 if ($tableArray = $this->map_needMapping($ORIG_tableName)) {
601 $this->map_remapSELECTQueryParts($select_fields,$from_table,$where_clause,$groupBy,$orderBy); // Variables passed by reference!
602 }
603
604 // Get handler key and select API:
605 $this->lastHandlerKey = $this->handler_getFromTableList($ORIG_tableName);
606 $hType = (string)$this->handlerCfg[$this->lastHandlerKey]['type'];
607 switch($hType) {
608 case 'native':
609 $this->lastQuery = $this->SELECTquery($select_fields,$from_table,$where_clause,$groupBy,$orderBy,$limit);
610 $sqlResult = mysql_query($this->lastQuery, $this->handlerInstance[$this->lastHandlerKey]['link']);
611 $this->resourceIdToTableNameMap[(string)$sqlResult] = $ORIG_tableName;
612 break;
613 case 'adodb':
614 if ($limit!='') {
615 $splitLimit = t3lib_div::intExplode(',',$limit); // Splitting the limit values:
616 if ($splitLimit[1]) { // If there are two parameters, do mapping differently than otherwise:
617 $numrows = $splitLimit[1];
618 $offset = $splitLimit[0];
619 } else {
620 $numrows = $splitLimit[0];
621 $offset = 0;
622 }
623
624 $sqlResult = $this->handlerInstance[$this->lastHandlerKey]->SelectLimit($this->SELECTquery($select_fields,$from_table,$where_clause,$groupBy,$orderBy), $numrows, $offset);
625 $this->lastQuery = $sqlResult->sql;
626 } else {
627 $this->lastQuery = $this->SELECTquery($select_fields,$from_table,$where_clause,$groupBy,$orderBy);
628 $sqlResult = $this->handlerInstance[$this->lastHandlerKey]->_Execute($this->lastQuery);
629 }
630 $sqlResult->TYPO3_DBAL_handlerType = 'adodb'; // Setting handler type in result object (for later recognition!)
631 $sqlResult->TYPO3_DBAL_tableList = $ORIG_tableName;
632 break;
633 case 'userdefined':
634 $sqlResult = $this->handlerInstance[$this->lastHandlerKey]->exec_SELECTquery($select_fields,$from_table,$where_clause,$groupBy,$orderBy,$limit);
635 if (is_object($sqlResult)) {
636 $sqlResult->TYPO3_DBAL_handlerType = 'userdefined'; // Setting handler type in result object (for later recognition!)
637 $sqlResult->TYPO3_DBAL_tableList = $ORIG_tableName;
638 }
639 break;
640 }
641
642 if ($this->printErrors && $this->sql_error()) {
643 debug(array($this->lastQuery, $this->sql_error()));
644 }
645
646 if ($this->debug) {
647 $this->debugHandler(
648 'exec_SELECTquery',
649 t3lib_div::milliseconds()-$pt,
650 array(
651 'handlerType' => $hType,
652 'args' => array($from_table,$select_fields,$where_clause,$groupBy,$orderBy,$limit),
653 'ORIG_from_table' => $ORIG_tableName
654 )
655 );
656 }
657
658 // Return result handler.
659 return $sqlResult;
660 }
661
662
663
664 /**************************************
665 *
666 * Query building
667 *
668 **************************************/
669
670 /**
671 * Creates an INSERT SQL-statement for $table from the array with field/value pairs $fields_values.
672 * Usage count/core: 4
673 *
674 * @param string See exec_INSERTquery()
675 * @param array See exec_INSERTquery()
676 * @param mixed See exec_INSERTquery()
677 * @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
678 * @depreciated use exec_INSERTquery() instead if possible!
679 */
680 function INSERTquery($table,$fields_values,$no_quote_fields='') {
681 // Table and fieldnames should be "SQL-injection-safe" when supplied to this function (contrary to values in the arrays which may be insecure).
682 if (is_array($fields_values) && count($fields_values)) {
683
684 if (is_string($no_quote_fields)) {
685 $no_quote_fields = explode(',',$no_quote_fields);
686 } elseif (!is_array($no_quote_fields)) {
687 $no_quote_fields = array();
688 }
689
690 $blobfields = array();
691 $nArr = array();
692 foreach($fields_values as $k => $v) {
693 if(!$this->runningNative() && $this->sql_field_metatype($table,$k) == 'B') {
694 // we skip the field in the regular INSERT statement, it is only in blobfields
695 $blobfields[$this->quoteFieldNames($k)] = $v;
696 }
697 else {
698 // Add slashes old-school:
699 // cast numerical values
700 $mt = $this->sql_field_metatype($table,$k);
701 $v = (($mt{0}=='I')||($mt{0}=='F')) ? (int)$v : $v;
702
703 $nArr[$this->quoteFieldNames($k)] = (!in_array($k,$no_quote_fields)) ? $this->fullQuoteStr($v, $table) : $v;
704 }
705 }
706 if(count($blobfields)) {
707 if(count($nArr)) {
708 $query[0] = 'INSERT INTO '.$this->quoteFromTables($table).'
709 (
710 '.implode(',
711 ',array_keys($nArr)).'
712 ) VALUES (
713 '.implode(',
714 ',$nArr).'
715 )';
716 }
717 $query[1] = $blobfields;
718 if ($this->debugOutput || $this->store_lastBuiltQuery) $this->debug_lastBuiltQuery = $query[0];
719 }
720 else {
721 $query = 'INSERT INTO '.$this->quoteFromTables($table).'
722 (
723 '.implode(',
724 ',array_keys($nArr)).'
725 ) VALUES (
726 '.implode(',
727 ',$nArr).'
728 )';
729
730 if ($this->debugOutput || $this->store_lastBuiltQuery) $this->debug_lastBuiltQuery = $query;
731 }
732
733 return $query;
734 }
735 }
736
737 /**
738 * Creates an UPDATE SQL-statement for $table where $where-clause (typ. 'uid=...') from the array with field/value pairs $fields_values.
739 * Usage count/core: 6
740 *
741 * @param string See exec_UPDATEquery()
742 * @param string See exec_UPDATEquery()
743 * @param array See exec_UPDATEquery()
744 * @param mixed See exec_UPDATEquery()
745 * @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
746 * @depreciated use exec_UPDATEquery() instead if possible!
747 */
748 function UPDATEquery($table,$where,$fields_values,$no_quote_fields='') {
749 // Table and fieldnames should be "SQL-injection-safe" when supplied to this function (contrary to values in the arrays which may be insecure).
750 if (is_string($where)) {
751 if (is_array($fields_values) && count($fields_values)) {
752
753 if (is_string($no_quote_fields)) {
754 $no_quote_fields = explode(',',$no_quote_fields);
755 } elseif (!is_array($no_quote_fields)) {
756 $no_quote_fields = array();
757 }
758
759 $blobfields = array();
760 $nArr = array();
761 foreach($fields_values as $k => $v) {
762 if(!$this->runningNative() && $this->sql_field_metatype($table,$k) == 'B') {
763 // we skip the field in the regular UPDATE statement, it is only in blobfields
764 $blobfields[$this->quoteFieldNames($k)] = $v;
765 }
766 else {
767 // Add slashes old-school:
768 // cast numeric values
769 $mt = $this->sql_field_metatype($table,$k);
770 $v = (($mt{0}=='I')||($mt{0}=='F')) ? (int)$v : $v;
771 $nArr[] = $this->quoteFieldNames($k).'='.((!in_array($k,$no_quote_fields)) ? $this->fullQuoteStr($v, $table) : $v);
772 }
773 }
774
775 if(count($blobfields)) {
776 if(count($nArr)) {
777 $query[0] = 'UPDATE '.$this->quoteFromTables($table).'
778 SET
779 '.implode(',
780 ',$nArr).
781 (strlen($where)>0 ? '
782 WHERE
783 '.$this->quoteWhereClause($where) : '');
784 }
785 $query[1] = $blobfields;
786 if ($this->debugOutput || $this->store_lastBuiltQuery) $this->debug_lastBuiltQuery = $query[0];
787 }
788 else {
789 $query = 'UPDATE '.$this->quoteFromTables($table).'
790 SET
791 '.implode(',
792 ',$nArr).
793 (strlen($where)>0 ? '
794 WHERE
795 '.$this->quoteWhereClause($where) : '');
796
797 if ($this->debugOutput || $this->store_lastBuiltQuery) $this->debug_lastBuiltQuery = $query;
798 }
799
800 return $query;
801 }
802 }
803 else {
804 die('<strong>TYPO3 Fatal Error:</strong> "Where" clause argument for UPDATE query was not a string in $this->UPDATEquery() !');
805 }
806 }
807
808 /**
809 * Creates a DELETE SQL-statement for $table where $where-clause
810 * Usage count/core: 3
811 *
812 * @param string See exec_DELETEquery()
813 * @param string See exec_DELETEquery()
814 * @return string Full SQL query for DELETE
815 * @depreciated use exec_DELETEquery() instead if possible!
816 */
817 function DELETEquery($table,$where) {
818 if (is_string($where)) {
819 $table = $this->quoteFromTables($table);
820 $where = $this->quoteWhereClause($where);
821
822 $query = parent::DELETEquery($table, $where);
823
824 if ($this->debugOutput || $this->store_lastBuiltQuery) $this->debug_lastBuiltQuery = $query;
825 return $query;
826 } else {
827 die('<strong>TYPO3 Fatal Error:</strong> "Where" clause argument for DELETE query was not a string in $this->DELETEquery() !');
828 }
829 }
830
831 /**
832 * Creates a SELECT SQL-statement
833 * Usage count/core: 11
834 *
835 * @param string See exec_SELECTquery()
836 * @param string See exec_SELECTquery()
837 * @param string See exec_SELECTquery()
838 * @param string See exec_SELECTquery()
839 * @param string See exec_SELECTquery()
840 * @param string See exec_SELECTquery()
841 * @return string Full SQL query for SELECT
842 * @depreciated use exec_SELECTquery() instead if possible!
843 */
844 function SELECTquery($select_fields,$from_table,$where_clause,$groupBy='',$orderBy='',$limit='') {
845
846 $select_fields = $this->quoteFieldNames($select_fields);
847 $from_table = $this->quoteFromTables($from_table);
848 $where_clause = $this->quoteWhereClause($where_clause);
849 $groupBy = $this->quoteGroupBy($groupBy);
850 $orderBy = $this->quoteOrderBy($orderBy);
851
852 // call parent method to build actual query
853 $query = parent::SELECTquery($select_fields,$from_table,$where_clause,$groupBy,$orderBy,$limit);
854
855 if ($this->debugOutput || $this->store_lastBuiltQuery) $this->debug_lastBuiltQuery = $query;
856
857 return $query;
858 }
859
860
861 /**************************************
862 *
863 * Functions for quoting table/field names
864 *
865 **************************************/
866
867 /**
868 * Quotes field (and table) names with the quote character suitable for the DB being used
869 * Use quoteFieldNames instead!
870 *
871 * @param string List of fields to be selected from DB
872 * @return string Quoted list of fields to be selected from DB
873 * @deprecated
874 */
875 function quoteSelectFields($select_fields) {
876 $this->quoteFieldNames($select_fields);
877 }
878
879 /**
880 * Quotes field (and table) names with the quote character suitable for the DB being used
881 *
882 * @param string List of fields to be used in query to DB
883 * @return string Quoted list of fields to be in query to DB
884 */
885 function quoteFieldNames($select_fields) {
886 if($select_fields == '') return '';
887 if($this->runningNative()) return $select_fields;
888
889 $select_fields = $this->SQLparser->parseFieldList($select_fields);
890 foreach($select_fields as $k => $v) {
891 if($select_fields[$k]['field'] != '' && $select_fields[$k]['field'] != '*') {
892 $select_fields[$k]['field'] = $this->handlerInstance[$this->lastHandlerKey]->nameQuote.$select_fields[$k]['field'].$this->handlerInstance[$this->lastHandlerKey]->nameQuote;
893 }
894 if($select_fields[$k]['table'] != '') {
895 $select_fields[$k]['table'] = $this->handlerInstance[$this->lastHandlerKey]->nameQuote.$select_fields[$k]['table'].$this->handlerInstance[$this->lastHandlerKey]->nameQuote;
896 }
897 if($select_fields[$k]['as'] != '') {
898 $select_fields[$k]['as'] = $this->handlerInstance[$this->lastHandlerKey]->nameQuote.$select_fields[$k]['as'].$this->handlerInstance[$this->lastHandlerKey]->nameQuote;
899 }
900 if(isset($select_fields[$k]['func_content.']) && $select_fields[$k]['func_content.'][0]['func_content'] != '*'){
901 if(strstr($select_fields[$k]['func_content.'][0]['func_content'],'.')) {
902 $select_fields[$k]['func_content.'][0]['func_content'] = $this->quoteFieldNames($select_fields[$k]['func_content.'][0]['func_content']);
903 $select_fields[$k]['func_content'] = $this->quoteFieldNames($select_fields[$k]['func_content']);
904 }
905 else {
906 $select_fields[$k]['func_content.'][0]['func_content'] = $this->handlerInstance[$this->lastHandlerKey]->nameQuote.$select_fields[$k]['func_content.'][0]['func_content'].$this->handlerInstance[$this->lastHandlerKey]->nameQuote;
907 $select_fields[$k]['func_content'] = $this->handlerInstance[$this->lastHandlerKey]->nameQuote.$select_fields[$k]['func_content'].$this->handlerInstance[$this->lastHandlerKey]->nameQuote;
908 }
909 }
910 }
911
912 return $this->SQLparser->compileFieldList($select_fields);
913 }
914
915 /**
916 * Quotes table names with the quote character suitable for the DB being used
917 *
918 * @param string List of tables to be selected from DB
919 * @return string Quoted list of tables to be selected from DB
920 */
921 function quoteFromTables($from_table) {
922 if($from_table == '') return '';
923 if($this->runningNative()) return $from_table;
924
925 $from_table = $this->SQLparser->parseFromTables($from_table);
926 foreach($from_table as $k => $v) {
927 $from_table[$k]['table'] = $this->handlerInstance[$this->lastHandlerKey]->nameQuote.$from_table[$k]['table'].$this->handlerInstance[$this->lastHandlerKey]->nameQuote;
928 if($from_table[$k]['as'] != '') {
929 $from_table[$k]['as'] = $this->handlerInstance[$this->lastHandlerKey]->nameQuote.$from_table[$k]['as'].$this->handlerInstance[$this->lastHandlerKey]->nameQuote;
930 }
931 if (is_array($v['JOIN'])) {
932 $from_table[$k]['JOIN']['withTable'] = $this->handlerInstance[$this->lastHandlerKey]->nameQuote.$from_table[$k]['JOIN']['withTable'].$this->handlerInstance[$this->lastHandlerKey]->nameQuote;
933 $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 : '';
934 $from_table[$k]['JOIN']['ON'][0]['field'] = $this->handlerInstance[$this->lastHandlerKey]->nameQuote.$from_table[$k]['JOIN']['ON'][0]['field'].$this->handlerInstance[$this->lastHandlerKey]->nameQuote;
935 $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 : '';
936 $from_table[$k]['JOIN']['ON'][1]['field'] = $this->handlerInstance[$this->lastHandlerKey]->nameQuote.$from_table[$k]['JOIN']['ON'][1]['field'].$this->handlerInstance[$this->lastHandlerKey]->nameQuote;
937 }
938 }
939 return $this->SQLparser->compileFromTables($from_table);
940 }
941
942 /**
943 * Quotes the field (and table) names within a where clause with the quote character suitable for the DB being used
944 *
945 * @param string A where clause that can e parsed by parseWhereClause
946 * @return string Usable where clause with quoted field/table names
947 */
948 function quoteWhereClause($where_clause) {
949 if($where_clause == '') return '';
950 if($this->runningNative()) return $where_clause;
951
952 $where_clause = $this->SQLparser->parseWhereClause($where_clause);
953 $where_clause = $this->_quoteWhereClause($where_clause);
954 $where_clause = $this->SQLparser->compileWhereClause($where_clause);
955
956 return $where_clause;
957 }
958
959 /**
960 * [Describe function...]
961 *
962 * @param [type] $$groupBy: ...
963 * @return [type] ...
964 */
965 function _quoteWhereClause($where_clause) {
966 foreach($where_clause as $k => $v) {
967 // Look for sublevel:
968 if (is_array($where_clause[$k]['sub'])) {
969 $where_clause[$k]['sub'] = $this->_quoteWhereClause($where_clause[$k]['sub']);
970 } else {
971 if($where_clause[$k]['table'] != '') {
972 $where_clause[$k]['table'] = $this->handlerInstance[$this->lastHandlerKey]->nameQuote.$where_clause[$k]['table'].$this->handlerInstance[$this->lastHandlerKey]->nameQuote;
973 }
974 if(!is_numeric($where_clause[$k]['field'])) {
975 $where_clause[$k]['field'] = $this->handlerInstance[$this->lastHandlerKey]->nameQuote.$where_clause[$k]['field'].$this->handlerInstance[$this->lastHandlerKey]->nameQuote;
976 }
977 }
978 if ($where_clause[$k]['comparator']) {
979 // Detecting value type; list or plain:
980 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'])))) {
981 $where_clause[$k]['value'][0] = $this->quoteFieldNames($where_clause[$k]['value'][0]);
982 }
983 }
984 }
985
986 return $where_clause;
987 }
988
989 /**
990 * [Describe function...]
991 *
992 * @param [type] $$groupBy: ...
993 * @return [type] ...
994 */
995 function quoteGroupBy($groupBy) {
996 if($groupBy == '') return '';
997 if($this->runningNative()) return $groupBy;
998
999 $groupBy = $this->SQLparser->parseFieldList($groupBy);
1000 foreach($groupBy as $k => $v) {
1001 $groupBy[$k]['field'] = $this->handlerInstance[$this->lastHandlerKey]->nameQuote.$groupBy[$k]['field'].$this->handlerInstance[$this->lastHandlerKey]->nameQuote;
1002 if($groupBy[$k]['table'] != '') {
1003 $groupBy[$k]['table'] = $this->handlerInstance[$this->lastHandlerKey]->nameQuote.$groupBy[$k]['table'].$this->handlerInstance[$this->lastHandlerKey]->nameQuote;
1004 }
1005 }
1006 return $this->SQLparser->compileFieldList($groupBy);
1007 }
1008
1009 /**
1010 * [Describe function...]
1011 *
1012 * @param [type] $$orderBy: ...
1013 * @return [type] ...
1014 */
1015 function quoteOrderBy($orderBy) {
1016 if($orderBy == '') return '';
1017 if($this->runningNative()) return $orderBy;
1018
1019 $orderBy = $this->SQLparser->parseFieldList($orderBy);
1020 foreach($orderBy as $k => $v) {
1021 $orderBy[$k]['field'] = $this->handlerInstance[$this->lastHandlerKey]->nameQuote.$orderBy[$k]['field'].$this->handlerInstance[$this->lastHandlerKey]->nameQuote;
1022 if($orderBy[$k]['table'] != '') {
1023 $orderBy[$k]['table'] = $this->handlerInstance[$this->lastHandlerKey]->nameQuote.$orderBy[$k]['table'].$this->handlerInstance[$this->lastHandlerKey]->nameQuote;
1024 }
1025 }
1026 return $this->SQLparser->compileFieldList($orderBy);
1027 }
1028
1029
1030
1031 /**************************************
1032 *
1033 * Various helper functions
1034 *
1035 **************************************/
1036
1037 /**
1038 * Escaping and quoting values for SQL statements.
1039 *
1040 * @param string Input string
1041 * @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!).
1042 * @return string Output string; Wrapped in single quotes and quotes in the string (" / ') and \ will be backslashed (or otherwise based on DBAL handler)
1043 * @see quoteStr()
1044 */
1045 function fullQuoteStr($str,$table) {
1046 return '\''.$this->quoteStr($str, $table).'\'';
1047 }
1048
1049 /**
1050 * Substitution for PHP function "addslashes()"
1051 * 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()!
1052 *
1053 * @param string Input string
1054 * @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!).
1055 * @return string Output string; Quotes (" / ') and \ will be backslashed (or otherwise based on DBAL handler)
1056 * @see quoteStr()
1057 */
1058 function quoteStr($str, $table) {
1059 $this->lastHandlerKey = $this->handler_getFromTableList($table);
1060 switch((string)$this->handlerCfg[$this->lastHandlerKey]['type']) {
1061 case 'native':
1062 $str = mysql_real_escape_string($str, $this->handlerInstance[$this->lastHandlerKey]['link']);
1063 break;
1064 case 'adodb':
1065 $str = substr($this->handlerInstance[$this->lastHandlerKey]->qstr($str),1,-1);
1066 break;
1067 case 'userdefined':
1068 $str = $this->handlerInstance[$this->lastHandlerKey]->quoteStr($str);
1069 break;
1070 default:
1071 die('No handler found!!!');
1072 break;
1073 }
1074
1075 return $str;
1076 }
1077
1078
1079 /**
1080 * Return MetaType for native field type (ADOdb only!)
1081 *
1082 * @param string native type as reported by admin_get_fields()
1083 * @param string Table name for which query type string. Important for detection of DBMS handler of the query!
1084 * @return string Meta type (currenly ADOdb syntax only, http://phplens.com/lens/adodb/docs-adodb.htm#metatype)
1085 */
1086 function MetaType($type,$table,$max_length=-1) {
1087 $this->lastHandlerKey = $this->handler_getFromTableList($table);
1088 switch((string)$this->handlerCfg[$this->lastHandlerKey]['type']) {
1089 case 'native':
1090 $str = $type;
1091 break;
1092 case 'adodb':
1093 $rs = $this->handlerInstance[$this->lastHandlerKey]->SelectLimit('SELECT * FROM '.$this->quoteFromTables($table),1);
1094 $str = $rs->MetaType($type, $max_length);
1095 break;
1096 case 'userdefined':
1097 $str = $this->handlerInstance[$this->lastHandlerKey]->MetaType($str,$table,$max_length);
1098 break;
1099 default:
1100 die('No handler found!!!');
1101 break;
1102 }
1103
1104 return $str;
1105 }
1106
1107
1108 /**
1109 * Return MetaType for native MySQL field type
1110 *
1111 * @param string native type as reported as in mysqldump files
1112 * @return string Meta type (currenly ADOdb syntax only, http://phplens.com/lens/adodb/docs-adodb.htm#metatype)
1113 */
1114 function MySQLMetaType($t) {
1115
1116 switch (strtoupper($t)) {
1117 case 'STRING':
1118 case 'CHAR':
1119 case 'VARCHAR':
1120 case 'TINYBLOB':
1121 case 'TINYTEXT':
1122 case 'ENUM':
1123 case 'SET': return 'C';
1124
1125 case 'TEXT':
1126 case 'LONGTEXT':
1127 case 'MEDIUMTEXT': return 'X';
1128
1129 case 'IMAGE':
1130 case 'LONGBLOB':
1131 case 'BLOB':
1132 case 'MEDIUMBLOB': return 'B';
1133
1134 case 'YEAR':
1135 case 'DATE': return 'D';
1136
1137 case 'TIME':
1138 case 'DATETIME':
1139 case 'TIMESTAMP': return 'T';
1140
1141 case 'FLOAT':
1142 case 'DOUBLE': return 'F';
1143
1144 case 'INT':
1145 case 'INTEGER':
1146 case 'TINYINT':
1147 case 'SMALLINT':
1148 case 'MEDIUMINT':
1149 case 'BIGINT': return 'I8'; // we always return I8 to be on the safe side. Under some circumstances the fields are to small otherwise...
1150
1151 default: return 'N';
1152 }
1153 }
1154
1155 /**
1156 * Return actual MySQL type for meta field type
1157 *
1158 * @param string Meta type (currenly ADOdb syntax only, http://phplens.com/lens/adodb/docs-adodb.htm#metatype)
1159 * @return string native type as reported as in mysqldump files, uppercase
1160 */
1161 function MySQLActualType($meta) {
1162 switch(strtoupper($meta)) {
1163 case 'C': return 'VARCHAR';
1164 case 'XL':
1165 case 'X': return 'LONGTEXT';
1166
1167 case 'C2': return 'VARCHAR';
1168 case 'X2': return 'LONGTEXT';
1169
1170 case 'B': return 'LONGBLOB';
1171
1172 case 'D': return 'DATE';
1173 case 'T': return 'DATETIME';
1174 case 'L': return 'TINYINT';
1175
1176 case 'I':
1177 case 'I1':
1178 case 'I2':
1179 case 'I4':
1180 case 'I8': return 'BIGINT'; // we only have I8 in DBAL, see MySQLMetaType()
1181
1182 case 'F': return 'DOUBLE';
1183 case 'N': return 'NUMERIC';
1184
1185 default: return $meta;
1186 }
1187 }
1188
1189
1190
1191
1192 /**************************************
1193 *
1194 * SQL wrapper functions (Overriding parent methods)
1195 * (For use in your applications)
1196 *
1197 **************************************/
1198
1199 /**
1200 * Returns the error status on the most recent sql() execution (based on $this->lastHandlerKey)
1201 *
1202 * @return string Handler error strings
1203 */
1204 function sql_error() {
1205
1206 switch($this->handlerCfg[$this->lastHandlerKey]['type']) {
1207 case 'native':
1208 $output = mysql_error($this->handlerInstance[$this->lastHandlerKey]['link']);
1209 break;
1210 case 'adodb':
1211 $output = $this->handlerInstance[$this->lastHandlerKey]->ErrorMsg();
1212 break;
1213 case 'userdefined':
1214 $output = $this->handlerInstance[$this->lastHandlerKey]->sql_error();
1215 break;
1216 }
1217 return $output;
1218 }
1219
1220 /**
1221 * Returns the number of selected rows.
1222 *
1223 * @param pointer Result pointer / DBAL object
1224 * @return integer Number of resulting rows.
1225 */
1226 function sql_num_rows(&$res) {
1227 if($res === false) return 0;
1228
1229 $handlerType = is_object($res) ? $res->TYPO3_DBAL_handlerType : 'native';
1230 switch($handlerType) {
1231 case 'native':
1232 $output = mysql_num_rows($res);
1233 break;
1234 case 'adodb':
1235 $output = method_exists($res, 'RecordCount') ? $res->RecordCount() : 0;
1236 break;
1237 case 'userdefined':
1238 $output = $res->sql_num_rows();
1239 break;
1240 }
1241 return $output;
1242 }
1243
1244 /**
1245 * Returns an associative array that corresponds to the fetched row, or FALSE if there are no more rows.
1246 *
1247 * @param pointer MySQL result pointer (of SELECT query) / DBAL object
1248 * @return array Associative array of result row.
1249 */
1250 function sql_fetch_assoc(&$res) {
1251 $output = array();
1252
1253 $handlerType = is_object($res) ? $res->TYPO3_DBAL_handlerType : (is_resource($res) ? 'native' : false);
1254 switch($handlerType) {
1255 case 'native':
1256 $output = mysql_fetch_assoc($res);
1257 $tableList = $this->resourceIdToTableNameMap[(string)$res]; // Reading list of tables from SELECT query:
1258 break;
1259 case 'adodb':
1260 // Check if method exists for the current $res object.
1261 // If a table exists in TCA but not in the db, a error
1262 // occured because $res is not a valid object.
1263 if(method_exists($res, 'FetchRow')) {
1264 $output = $res->FetchRow();
1265 $tableList = $res->TYPO3_DBAL_tableList; // Reading list of tables from SELECT query:
1266
1267 // Removing all numeric/integer keys.
1268 // A workaround because in ADOdb we would need to know what we want before executing the query...
1269 if (is_array($output)) {
1270 foreach($output as $key => $value) {
1271 if (is_integer($key)) unset($output[$key]);
1272 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.
1273 }
1274 }
1275 }
1276 break;
1277 case 'userdefined':
1278 $output = $res->sql_fetch_assoc();
1279 $tableList = $res->TYPO3_DBAL_tableList; // Reading list of tables from SELECT query:
1280 break;
1281 }
1282
1283 // Table/Fieldname mapping:
1284 if (is_array($output)) {
1285 if ($tables = $this->map_needMapping($tableList,TRUE)) {
1286 $output = $this->map_assocArray($output,$tables,1);
1287 }
1288 }
1289
1290 // Return result:
1291 return $output;
1292 }
1293
1294 /**
1295 * Returns an array that corresponds to the fetched row, or FALSE if there are no more rows.
1296 * The array contains the values in numerical indices.
1297 *
1298 * @param pointer MySQL result pointer (of SELECT query) / DBAL object
1299 * @return array Array with result rows.
1300 */
1301 function sql_fetch_row(&$res) {
1302 $handlerType = is_object($res) ? $res->TYPO3_DBAL_handlerType : 'native';
1303 switch($handlerType) {
1304 case 'native':
1305 $output = mysql_fetch_row($res);
1306 break;
1307 case 'adodb':
1308 // Check if method exists for the current $res object.
1309 // If a table exists in TCA but not in the db, a error
1310 // occured because $res is not a valid object.
1311 if(method_exists($res, 'FetchRow')) {
1312 $output = $res->FetchRow();
1313
1314 // Removing all assoc. keys.
1315 // A workaround because in ADOdb we would need to know what we want before executing the query...
1316 if (is_array($output)) {
1317 foreach($output as $key => $value) {
1318 if (!is_integer($key)) unset($output[$key]);
1319 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.
1320 }
1321 }
1322 }
1323 break;
1324 case 'userdefined':
1325 $output = $res->sql_fetch_row();
1326 break;
1327 }
1328 return $output;
1329 }
1330
1331 /**
1332 * Free result memory / unset result object
1333 *
1334 * @param pointer MySQL result pointer to free / DBAL object
1335 * @return boolean Returns TRUE on success or FALSE on failure.
1336 */
1337 function sql_free_result(&$res) {
1338 if($res===false) return false;
1339
1340 $handlerType = is_object($res) ? $res->TYPO3_DBAL_handlerType : 'native';
1341 switch($handlerType) {
1342 case 'native':
1343 $output = mysql_free_result($res);
1344 break;
1345 case 'adodb':
1346 if(method_exists($res, 'Close')) {
1347 $res->Close();
1348 unset($res);
1349 $output = true;
1350 } else {
1351 $output = false;
1352 }
1353 break;
1354 case 'userdefined':
1355 unset($res);
1356 break;
1357 }
1358 return $output;
1359 }
1360
1361 /**
1362 * Get the ID generated from the previous INSERT operation
1363 *
1364 * @return integer The uid of the last inserted record.
1365 */
1366 function sql_insert_id() {
1367
1368 switch($this->handlerCfg[$this->lastHandlerKey]['type']) {
1369 case 'native':
1370 $output = mysql_insert_id($this->handlerInstance[$this->lastHandlerKey]['link']);
1371 break;
1372 case 'adodb':
1373 $output = $this->handlerInstance[$this->lastHandlerKey]->last_insert_id;
1374 break;
1375 case 'userdefined':
1376 $output = $this->handlerInstance[$this->lastHandlerKey]->sql_insert_id();
1377 break;
1378 }
1379 return $output;
1380 }
1381
1382 /**
1383 * Returns the number of rows affected by the last INSERT, UPDATE or DELETE query
1384 *
1385 * @return integer Number of rows affected by last query
1386 */
1387 function sql_affected_rows() {
1388
1389 switch($this->handlerCfg[$this->lastHandlerKey]['type']) {
1390 case 'native':
1391 $output = mysql_affected_rows();
1392 break;
1393 case 'adodb':
1394 $output = $this->handlerInstance[$this->lastHandlerKey]->Affected_Rows();
1395 break;
1396 case 'userdefined':
1397 $output = $this->handlerInstance[$this->lastHandlerKey]->sql_affected_rows();
1398 break;
1399 }
1400 return $output;
1401 }
1402
1403 /**
1404 * Move internal result pointer
1405 *
1406 * @param pointer MySQL result pointer (of SELECT query) / DBAL object
1407 * @param integer Seek result number.
1408 * @return boolean Returns TRUE on success or FALSE on failure.
1409 */
1410 function sql_data_seek(&$res,$seek) {
1411
1412 $handlerType = is_object($res) ? $res->TYPO3_DBAL_handlerType : 'native';
1413 switch($handlerType) {
1414 case 'native':
1415 $output = mysql_data_seek($res,$seek);
1416 break;
1417 case 'adodb':
1418 $output = $res->Move($seek);
1419 break;
1420 case 'userdefined':
1421 $output = $res->sql_data_seek($seek);
1422 break;
1423 }
1424 return $output;
1425 }
1426
1427 /**
1428 * Get the type of the specified field in a result
1429 *
1430 * If the first parameter is a string, it is used as table name for the lookup.
1431 *
1432 * @param pointer MySQL result pointer (of SELECT query) / DBAL object / table name
1433 * @param integer Field index. In case of ADOdb a string (field name!) FIXME
1434 * @return string Returns the type of the specified field index
1435 */
1436 function sql_field_metatype($table,$field) {
1437 return $this->cache_fieldType[$table][$field]['metaType'];
1438 }
1439
1440 /**
1441 * Get the type of the specified field in a result
1442 *
1443 * If the first parameter is a string, it is used as table name for the lookup.
1444 *
1445 * @param pointer MySQL result pointer (of SELECT query) / DBAL object / table name
1446 * @param integer Field index. In case of ADOdb a string (field name!) FIXME
1447 * @return string Returns the type of the specified field index
1448 */
1449 function sql_field_type(&$res,$pointer) {
1450 if($res === null) {
1451 debug(array('no res in sql_field_type!'));
1452 return 'text';
1453 }
1454 else if(is_string($res)){
1455 if($res == 'tx_dbal_debuglog') return 'text';
1456 $handlerType = 'adodb';
1457 }
1458 else {
1459 $handlerType = is_object($res) ? $res->TYPO3_DBAL_handlerType : 'native';
1460 }
1461
1462 switch($handlerType) {
1463 case 'native':
1464 $output = mysql_field_type($res,$pointer);
1465 break;
1466 case 'adodb':
1467 if(is_string($pointer)){
1468 $output = $this->cache_fieldType[$res][$pointer]['type'];
1469 }
1470
1471 break;
1472 case 'userdefined':
1473 $output = $res->sql_field_type($pointer);
1474 break;
1475 }
1476
1477 return $output;
1478 }
1479
1480
1481
1482
1483
1484
1485
1486
1487 /**********
1488 *
1489 * Legacy functions, bound to _DEFAULT handler. (Overriding parent methods)
1490 * Depreciated.
1491 *
1492 **********/
1493
1494 /**
1495 * Executes query (on DEFAULT handler!)
1496 * DEPRECIATED - use exec_* functions from this class instead!
1497 *
1498 * @param string Database name
1499 * @param string Query to execute
1500 * @return pointer Result pointer
1501 * @depreciated
1502 */
1503 function sql($db,$query) {
1504 return $this->sql_query($query);
1505 }
1506
1507 /**
1508 * Executes query (on DEFAULT handler!)
1509 * DEPRECIATED - use exec_* functions from this class instead!
1510 *
1511 * If you don't, anything that uses not the _DEFAULT handler will break!
1512 *
1513 * @param string Query to execute
1514 * @return pointer Result pointer / DBAL object
1515 * @depreciated
1516 */
1517 function sql_query($query) {
1518
1519 switch($this->handlerCfg['_DEFAULT']['type']) {
1520 case 'native':
1521 $sqlResult = mysql_query($query, $this->handlerInstance['_DEFAULT']['link']);
1522 break;
1523 case 'adodb':
1524 $sqlResult = $this->handlerInstance['_DEFAULT']->Execute($query);
1525 $sqlResult->TYPO3_DBAL_handlerType = 'adodb';
1526 break;
1527 case 'userdefined':
1528 $sqlResult = $this->handlerInstance['_DEFAULT']->sql_query($query);
1529 $sqlResult->TYPO3_DBAL_handlerType = 'userdefined';
1530 break;
1531 }
1532
1533 if ($this->printErrors && $this->sql_error()) {
1534 debug(array($this->lastQuery, $this->sql_error()));
1535 }
1536
1537 return $sqlResult;
1538 }
1539
1540 /**
1541 * Opening the _DEFAULT connection handler to the database.
1542 * This is typically done by the scripts "init.php" in the backend or "index_ts.php" in the frontend (tslib_fe->connectToMySQL())
1543 * You wouldn't need to use this at any time - let TYPO3 core handle this.
1544 *
1545 * @param string Database host IP/domain
1546 * @param string Username to connect with.
1547 * @param string Password to connect with.
1548 * @return mixed Returns handler connection value
1549 * @depreciated
1550 * @see handler_init()
1551 */
1552 function sql_pconnect($TYPO3_db_host, $TYPO3_db_username, $TYPO3_db_password) {
1553 // Overriding the _DEFAULT handler configuration of username, password, localhost and database name:
1554 $this->handlerCfg['_DEFAULT']['config']['username'] = $TYPO3_db_username;
1555 $this->handlerCfg['_DEFAULT']['config']['password'] = $TYPO3_db_password;
1556 $this->handlerCfg['_DEFAULT']['config']['host'] = $TYPO3_db_host;
1557 $this->handlerCfg['_DEFAULT']['config']['database'] = TYPO3_db;
1558
1559 // Initializing and output value:
1560 $sqlResult = $this->handler_init('_DEFAULT');
1561 return $sqlResult;
1562 }
1563
1564 /**
1565 * Select database for _DEFAULT handler.
1566 *
1567 * @param string Database to connect to.
1568 * @return boolean Always returns true; function is obsolete, database selection is made in handler_init() function!
1569 * @depreciated
1570 */
1571 function sql_select_db($TYPO3_db) {
1572 return TRUE;
1573 }
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589 /**************************************
1590 *
1591 * SQL admin functions
1592 * (For use in the Install Tool and Extension Manager)
1593 *
1594 **************************************/
1595
1596 /**
1597 * Listing databases from current MySQL connection. NOTICE: It WILL try to select those databases and thus break selection of current database.
1598 * Use in Install Tool only!
1599 * Usage count/core: 1
1600 *
1601 * @return array Each entry represents a database name
1602 */
1603 function admin_get_dbs() {
1604 $dbArr = array();
1605 switch($this->handlerCfg['_DEFAULT']['type']) {
1606 case 'native':
1607 $db_list = mysql_list_dbs($this->link);
1608 while ($row = mysql_fetch_object($db_list)) {
1609 if ($this->sql_select_db($row->Database)) {
1610 $dbArr[] = $row->Database;
1611 }
1612 }
1613 break;
1614 case 'adodb':
1615 // check needed for install tool - otherwise it will just die because the call to
1616 // MetaDatabases is done on a stdClass instance
1617 if(method_exists($this->handlerInstance['_DEFAULT'],'MetaDatabases')) {
1618 $sqlDBs = $this->handlerInstance['_DEFAULT']->MetaDatabases();
1619 if(is_array($sqlDBs)) {
1620 foreach($sqlDBs as $k => $theDB) {
1621 $dbArr[] = $theDB;
1622 }
1623 }
1624 }
1625 break;
1626 case 'userdefined':
1627 $dbArr = $this->handlerInstance['_DEFAULT']->admin_get_tables();
1628 break;
1629 }
1630
1631 return $dbArr;
1632 }
1633
1634 /**
1635 * Returns the list of tables from the system (quering the DBMSs)
1636 * It looks up all tables from the DBMS of the _DEFAULT handler and then add all tables *configured* to be managed by other handlers
1637 *
1638 * 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.
1639 *
1640 * @return array Tables in an array (tablename is in both key and value)
1641 * @todo Should the check for Oracle Recycle Bin stuff be moved elsewhere?
1642 */
1643 function admin_get_tables() {
1644 $whichTables = array();
1645
1646 // Getting real list of tables:
1647 switch($this->handlerCfg['_DEFAULT']['type']) {
1648 case 'native':
1649 $tables_result = mysql_list_tables(TYPO3_db, $this->handlerInstance['_DEFAULT']['link']);
1650 if (!$this->sql_error()) {
1651 while ($theTable = $this->sql_fetch_assoc($tables_result)) {
1652 $whichTables[current($theTable)] = current($theTable);
1653 }
1654 }
1655 break;
1656 case 'adodb':
1657 $sqlTables = $this->handlerInstance['_DEFAULT']->MetaTables('TABLES');
1658 while (list($k, $theTable) = each($sqlTables)) {
1659 if(preg_match('/BIN\$/', $theTable)) continue; // skip tables from the Oracle 10 Recycle Bin
1660 $whichTables[$theTable] = $theTable;
1661 }
1662 break;
1663 case 'userdefined':
1664 $whichTables = $this->handlerInstance['_DEFAULT']->admin_get_tables();
1665 break;
1666 }
1667
1668 // Check mapping:
1669 if (is_array($this->mapping) && count($this->mapping)) {
1670
1671 // Mapping table names in reverse, first getting list of real table names:
1672 $tMap = array();
1673 foreach($this->mapping as $tN => $tMapInfo) {
1674 if (isset($tMapInfo['mapTableName'])) $tMap[$tMapInfo['mapTableName']]=$tN;
1675 }
1676
1677 // Do mapping:
1678 $newList=array();
1679 foreach($whichTables as $tN) {
1680 if (isset($tMap[$tN])) $tN = $tMap[$tN];
1681 $newList[$tN] = $tN;
1682 }
1683
1684 $whichTables = $newList;
1685 }
1686
1687 // Adding tables configured to reside in other DBMS (handler by other handlers than the default):
1688 if (is_array($this->table2handlerKeys)) {
1689 foreach($this->table2handlerKeys as $key => $handlerKey) {
1690 $whichTables[$key] = $key;
1691 }
1692 }
1693
1694 return $whichTables;
1695 }
1696
1697 /**
1698 * Returns information about each field in the $table (quering the DBMS)
1699 * In a DBAL this should look up the right handler for the table and return compatible information
1700 * 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
1701 *
1702 * @param string Table name
1703 * @return array Field information in an associative array with fieldname => field row
1704 */
1705 function admin_get_fields($tableName) {
1706 $output = array();
1707
1708 // Do field mapping if needed:
1709 $ORIG_tableName = $tableName;
1710 if ($tableArray = $this->map_needMapping($tableName)) {
1711
1712 // Table name:
1713 if ($this->mapping[$tableName]['mapTableName']) {
1714 $tableName = $this->mapping[$tableName]['mapTableName'];
1715 }
1716 }
1717
1718 // Find columns
1719 $this->lastHandlerKey = $this->handler_getFromTableList($ORIG_tableName);
1720 switch((string)$this->handlerCfg[$this->lastHandlerKey]['type']) {
1721 case 'native':
1722 $columns_res = mysql_query('SHOW columns FROM '.$tableName, $this->handlerInstance[$this->lastHandlerKey]['link']);
1723 while($fieldRow = mysql_fetch_assoc($columns_res)) {
1724 $output[$fieldRow['Field']] = $fieldRow;
1725 }
1726 break;
1727 case 'adodb':
1728 $fieldRows = $this->handlerInstance[$this->lastHandlerKey]->MetaColumns($tableName, false);
1729 foreach($fieldRows as $k => $fieldRow) {
1730 settype($fieldRow, 'array');
1731 $fieldRow['Field'] = $fieldRow['name'];
1732 $ntype = $this->MySQLActualType($this->MetaType($fieldRow['type'],$tableName));
1733 $ntype .= (($fieldRow['max_length'] != -1) ? (($ntype == 'INT') ? '(11)' :'('.$fieldRow['max_length'].')') : '');
1734 $fieldRow['Type'] = strtolower($ntype);
1735 $fieldRow['Null'] = '';
1736 $fieldRow['Key'] = '';
1737 $fieldRow['Default'] = $fieldRow['default_value'];
1738 $fieldRow['Extra'] = '';
1739 $output[$fieldRow['name']] = $fieldRow;
1740 }
1741 break;
1742 case 'userdefined':
1743 $output = $this->handlerInstance[$this->lastHandlerKey]->admin_get_fields($tableName);
1744 break;
1745 }
1746
1747 // mapping should be done:
1748 if (is_array($tableArray) && is_array($this->mapping[$ORIG_tableName]['mapFieldNames'])) {
1749 $revFields = array_flip($this->mapping[$ORIG_tableName]['mapFieldNames']);
1750
1751 $newOutput = array();
1752 foreach($output as $fN => $fInfo) {
1753 if (isset($revFields[$fN])) {
1754 $fN = $revFields[$fN];
1755 $fInfo['Field'] = $fN;
1756 }
1757 $newOutput[$fN] = $fInfo;
1758 }
1759 $output = $newOutput;
1760 }
1761
1762 return $output;
1763 }
1764
1765 /**
1766 * Returns information about each index key in the $table (quering the DBMS)
1767 * In a DBAL this should look up the right handler for the table and return compatible information
1768 *
1769 * @param string Table name
1770 * @return array Key information in a numeric array
1771 */
1772 function admin_get_keys($tableName) {
1773 $output = array();
1774
1775 // Do field mapping if needed:
1776 $ORIG_tableName = $tableName;
1777 if ($tableArray = $this->map_needMapping($tableName)) {
1778
1779 // Table name:
1780 if ($this->mapping[$tableName]['mapTableName']) {
1781 $tableName = $this->mapping[$tableName]['mapTableName'];
1782 }
1783 }
1784
1785 // Find columns
1786 $this->lastHandlerKey = $this->handler_getFromTableList($ORIG_tableName);
1787 switch((string)$this->handlerCfg[$this->lastHandlerKey]['type']) {
1788 case 'native':
1789 $keyRes = mysql_query('SHOW keys FROM '.$tableName, $this->handlerInstance[$this->lastHandlerKey]['link']);
1790 while($keyRow = mysql_fetch_assoc($keyRes)) {
1791 $output[] = $keyRow;
1792 }
1793 break;
1794 case 'adodb':
1795 $keyRows = $this->handlerInstance[$this->lastHandlerKey]->MetaIndexes($tableName);
1796 if($keyRows !== false) {
1797 while (list($k, $theKey) = each($keyRows)) {
1798 $theKey['Table'] = $tableName;
1799 $theKey['Non_unique'] = (int) !$theKey['unique'];
1800 $theKey['Key_name'] = str_replace($tableName.'_','',$k);
1801
1802 // the following are probably not needed anyway...
1803 $theKey['Collation'] = '';
1804 $theKey['Cardinality'] = '';
1805 $theKey['Sub_part'] = '';
1806 $theKey['Packed'] = '';
1807 $theKey['Null'] = '';
1808 $theKey['Index_type'] = '';
1809 $theKey['Comment'] = '';
1810
1811 // now map multiple fields into multiple rows (we mimic MySQL, remember...)
1812 $keycols = $theKey['columns'];
1813 while (list($c, $theCol) = each($keycols)) {
1814 $theKey['Seq_in_index'] = $c+1;
1815 $theKey['Column_name'] = $theCol;
1816 $output[] = $theKey;
1817 }
1818 }
1819 }
1820 $priKeyRow = $this->handlerInstance[$this->lastHandlerKey]->MetaPrimaryKeys($tableName);
1821 $theKey = array();
1822 $theKey['Table'] = $tableName;
1823 $theKey['Non_unique'] = 0;
1824 $theKey['Key_name'] = 'PRIMARY';
1825
1826 // the following are probably not needed anyway...
1827 $theKey['Collation'] = '';
1828 $theKey['Cardinality'] = '';
1829 $theKey['Sub_part'] = '';
1830 $theKey['Packed'] = '';
1831 $theKey['Null'] = '';
1832 $theKey['Index_type'] = '';
1833 $theKey['Comment'] = '';
1834
1835 // now map multiple fields into multiple rows (we mimic MySQL, remember...)
1836 if($priKeyRow !== false) {
1837 while (list($c, $theCol) = each($priKeyRow)) {
1838 $theKey['Seq_in_index'] = $c+1;
1839 $theKey['Column_name'] = $theCol;
1840 $output[] = $theKey;
1841 }
1842 }
1843 break;
1844 case 'userdefined':
1845 $output = $this->handlerInstance[$this->lastHandlerKey]->admin_get_keys($tableName);
1846 break;
1847 }
1848
1849 // mapping should be done:
1850 if (is_array($tableArray) && is_array($this->mapping[$ORIG_tableName]['mapFieldNames'])) {
1851 $revFields = array_flip($this->mapping[$ORIG_tableName]['mapFieldNames']);
1852
1853 $newOutput = array();
1854 foreach($output as $kN => $kInfo) {
1855 // Table:
1856 $kInfo['Table'] = $ORIG_tableName;
1857
1858 // Column
1859 if (isset($revFields[$kInfo['Column_name']])) {
1860 $kInfo['Column_name'] = $revFields[$kInfo['Column_name']];
1861 }
1862
1863 // Write it back:
1864 $newOutput[$kN] = $kInfo;
1865 }
1866 $output = $newOutput;
1867 }
1868
1869 return $output;
1870 }
1871
1872 /**
1873 * mysql() wrapper function, used by the Install Tool and EM for all queries regarding management of the database!
1874 *
1875 * @param string Query to execute
1876 * @return pointer Result pointer
1877 */
1878 function admin_query($query) {
1879 $parsedQuery = $this->SQLparser->parseSQL($query);
1880 $ORIG_table = $parsedQuery['TABLE'];
1881
1882 if (is_array($parsedQuery)) {
1883
1884 // Process query based on type:
1885 switch($parsedQuery['type']) {
1886 case 'CREATETABLE':
1887 case 'ALTERTABLE':
1888 case 'DROPTABLE':
1889 if(file_exists(PATH_typo3conf.'temp_fieldInfo.php')) unlink(PATH_typo3conf.'temp_fieldInfo.php');
1890 $this->map_genericQueryParsed($parsedQuery);
1891 break;
1892 case 'INSERT':
1893 $this->map_genericQueryParsed($parsedQuery);
1894 break;
1895 case 'CREATEDATABASE':
1896 die('Creating a database with DBAL is not supported. Did you really read the manual?');
1897 break;
1898 default:
1899 die('ERROR: Invalid Query type ('.$parsedQuery['type'].') for ->admin_query() function!: "'.htmlspecialchars($query).'"');
1900 break;
1901 }
1902
1903 // Setting query array (for other applications to access if needed)
1904 $this->lastParsedAndMappedQueryArray = $parsedQuery;
1905
1906 // Execute query (based on handler derived from the TABLE name which we actually know for once!)
1907 $this->lastHandlerKey = $this->handler_getFromTableList($ORIG_table);
1908 switch((string)$this->handlerCfg[$this->lastHandlerKey]['type']) {
1909 case 'native':
1910 // Compiling query:
1911 $compiledQuery = $this->SQLparser->compileSQL($this->lastParsedAndMappedQueryArray);
1912
1913 return mysql_query($compiledQuery[0], $this->link);
1914 break;
1915 case 'adodb':
1916 // Compiling query:
1917 $compiledQuery = $this->SQLparser->compileSQL($this->lastParsedAndMappedQueryArray);
1918 if($this->lastParsedAndMappedQueryArray['type']=='INSERT') {
1919 return $this->exec_INSERTquery($this->lastParsedAndMappedQueryArray['TABLE'],$compiledQuery);
1920 }
1921 return $this->handlerInstance[$this->lastHandlerKey]->DataDictionary->ExecuteSQLArray($compiledQuery);
1922 break;
1923 case 'userdefined':
1924 // Compiling query:
1925 $compiledQuery = $this->SQLparser->compileSQL($this->lastParsedAndMappedQueryArray);
1926
1927 return $this->handlerInstance[$this->lastHandlerKey]->admin_query($compiledQuery);
1928 break;
1929 }
1930 } else die('ERROR: Query could not be parsed: "'.htmlspecialchars($parsedQuery).'". Query: "'.htmlspecialchars($query).'"');
1931 }
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942 /************************************
1943 *
1944 * Handler management
1945 *
1946 **************************************/
1947
1948 /**
1949 * Return the handler key pointing to an appropriate database handler as found in $this->handlerCfg array
1950 * 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!)
1951 *
1952 * @param string Table list, eg. "pages" or "pages, tt_content" or "pages AS A, tt_content AS B"
1953 * @return string Handler key (see $this->handlerCfg array) for table
1954 */
1955 function handler_getFromTableList($tableList) {
1956
1957 $key = $tableList;
1958
1959 if (!isset($this->cache_handlerKeyFromTableList[$key])) {
1960
1961 // Get tables separated:
1962 $_tableList = $tableList;
1963 $tableArray = $this->SQLparser->parseFromTables($_tableList);
1964
1965 // If success, traverse the tables:
1966 if (is_array($tableArray) && count($tableArray)) {
1967 foreach($tableArray as $vArray) {
1968
1969 // Find handler key, select "_DEFAULT" if none is specifically configured:
1970 $handlerKey = $this->table2handlerKeys[$vArray['table']] ? $this->table2handlerKeys[$vArray['table']] : '_DEFAULT';
1971
1972 // In case of separate handler keys for joined tables:
1973 if ($outputHandlerKey && $handlerKey != $outputHandlerKey) {
1974 die('DBAL fatal error: Tables in this list "'.$tableList.'" didn\'t use the same DB handler!');
1975 }
1976
1977 $outputHandlerKey = $handlerKey;
1978 }
1979
1980 // Check initialized state; if handler is NOT initialized (connected) then we will connect it!
1981 if (!isset($this->handlerInstance[$outputHandlerKey])) {
1982 $this->handler_init($outputHandlerKey);
1983 }
1984
1985 // Return handler key:
1986 $this->cache_handlerKeyFromTableList[$key] = $outputHandlerKey;
1987 } else {
1988 die('DBAL fatal error: No handler found in handler_getFromTableList() for: "'.$tableList.'" ('.$tableArray.')');
1989 }
1990 }
1991
1992 return $this->cache_handlerKeyFromTableList[$key];
1993 }
1994
1995 /**
1996 * Initialize handler (connecting to database)
1997 *
1998 * @param string Handler key
1999 * @return boolean If connection went well, return true
2000 * @see handler_getFromTableList()
2001 */
2002 function handler_init($handlerKey) {
2003
2004 // Find handler configuration:
2005 $cfgArray = $this->handlerCfg[$handlerKey];
2006 $handlerType = (string)$cfgArray['type'];
2007 $output = FALSE;
2008
2009 if (is_array($cfgArray)) {
2010 switch($handlerType) {
2011 case 'native':
2012 if ($GLOBALS['TYPO3_CONF_VARS']['SYS']['no_pconnect']) {
2013 $link = mysql_connect($cfgArray['config']['host'].(isset($cfgArray['config']['port']) ? ':'.$cfgArray['config']['port'] : ''), $cfgArray['config']['username'], $cfgArray['config']['password'], true);
2014 } else {
2015 $link = mysql_pconnect($cfgArray['config']['host'].(isset($cfgArray['config']['port']) ? ':'.$cfgArray['config']['port'] : ''), $cfgArray['config']['username'], $cfgArray['config']['password']);
2016 }
2017
2018 // Set handler instance:
2019 $this->handlerInstance[$handlerKey] = array('handlerType' => 'native', 'link' => $link);
2020
2021 // If link succeeded:
2022 if ($link) {
2023 // For default, set ->link (see t3lib_DB)
2024 if ($handlerKey == '_DEFAULT') {
2025 $this->link = $link;
2026 }
2027
2028 // Select database as well:
2029 if (mysql_select_db($cfgArray['config']['database'], $link)) {
2030 $output = TRUE;
2031 }
2032 $setDBinit = t3lib_div::trimExplode(chr(10), $GLOBALS['TYPO3_CONF_VARS']['SYS']['setDBinit'], 1);
2033 foreach ($setDBinit as $v) {
2034 if (mysql_query($v, $this->link) === FALSE) {
2035 t3lib_div::sysLog('Could not initialize DB connection with query "'.$v.'".','Core',3);
2036 }
2037 }
2038 } else {
2039 t3lib_div::sysLog('Could not connect to MySQL server '.$cfgArray['config']['host'].' with user '.$cfgArray['config']['username'].'.','Core',4);
2040 }
2041 break;
2042 case 'adodb':
2043 $output = true;
2044 require_once(t3lib_extMgm::extPath('adodb').'adodb/adodb.inc.php');
2045 if(!defined('ADODB_FORCE_NULLS')) define('ADODB_FORCE_NULLS', 1);
2046 $GLOBALS['ADODB_FORCE_TYPE'] = ADODB_FORCE_VALUE;
2047 $GLOBALS['ADODB_FETCH_MODE'] = ADODB_FETCH_BOTH;
2048
2049 $this->handlerInstance[$handlerKey] = &ADONewConnection($cfgArray['config']['driver']);
2050 if ($GLOBALS['TYPO3_CONF_VARS']['SYS']['no_pconnect']) {
2051 $this->handlerInstance[$handlerKey]->Connect($cfgArray['config']['host'].(isset($cfgArray['config']['port']) ? ':'.$cfgArray['config']['port'] : ''),$cfgArray['config']['username'],$cfgArray['config']['password'],$cfgArray['config']['database']);
2052 } else {
2053 $this->handlerInstance[$handlerKey]->PConnect($cfgArray['config']['host'].(isset($cfgArray['config']['port']) ? ':'.$cfgArray['config']['port'] : ''),$cfgArray['config']['username'],$cfgArray['config']['password'],$cfgArray['config']['database']);
2054 }
2055 if(!$this->handlerInstance[$handlerKey]->isConnected()) {
2056 $dsn = $cfgArray['config']['driver'].'://'.$cfgArray['config']['username'].
2057 (strlen($cfgArray['config']['password']) ? ':XXXX@' : '').
2058 $cfgArray['config']['host'].(isset($cfgArray['config']['port']) ? ':'.$cfgArray['config']['port'] : '').'/'.$cfgArray['config']['database'].
2059 ($GLOBALS['TYPO3_CONF_VARS']['SYS']['no_pconnect'] ? '' : '?persistent=1');
2060 t3lib_div::sysLog('Could not connect to DB server using ADOdb on '.$cfgArray['config']['host'].' with user '.$cfgArray['config']['username'].'.','Core',4);
2061 error_log('DBAL error: Connection to '.$dsn.' failed. Maybe PHP doesn\'t support the database?');
2062 $output = false;
2063 } else {
2064 $this->handlerInstance[$handlerKey]->DataDictionary = NewDataDictionary($this->handlerInstance[$handlerKey]);
2065 $this->handlerInstance[$handlerKey]->last_insert_id = 0;
2066 $this->handlerInstance[$handlerKey]->sequenceStart = $cfgArray['config']['sequenceStart'];
2067 }
2068 break;
2069 case 'userdefined':
2070 // Find class file:
2071 $fileName = t3lib_div::getFileAbsFileName($cfgArray['config']['classFile']);
2072 if (@is_file($fileName)) {
2073 require_once($fileName);
2074 } else die('DBAL error: "'.$fileName.'" was not a file to include.');
2075
2076 // Initialize:
2077 $this->handlerInstance[$handlerKey] = t3lib_div::makeInstance($cfgArray['config']['class']);
2078 $this->handlerInstance[$handlerKey]->init($cfgArray,$this);
2079
2080 if (is_object($this->handlerInstance[$handlerKey])) {
2081 $output = TRUE;
2082 }
2083 break;
2084 default:
2085 die('ERROR: Invalid handler type: "'.$cfgArray['type'].'"');
2086 break;
2087 }
2088
2089 return $output;
2090 } else die('ERROR: No handler for key "'.$handlerKey.'"');
2091 }
2092
2093
2094 /**
2095 * Checks whether the DBAL is currently inside an operation running on the "native" DB handler (i.e. MySQL)
2096 *
2097 * @return boolean True if running on "native" DB handler (i.e. MySQL)
2098 */
2099 function runningNative() {
2100 return ((string)$this->handlerCfg[$this->lastHandlerKey]['type']==='native');
2101 }
2102
2103
2104 /**
2105 * Checks whether the ADOdb handler is running with a driver that contains the argument
2106 *
2107 * @param string $driver Driver name, matched with strstr().
2108 * @return boolean True if running with the given driver
2109 */
2110 function runningADOdbDriver($driver) {
2111 return strstr($this->handlerCfg[$this->lastHandlerKey]['config']['driver'], $driver);
2112 }
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123 /************************************
2124 *
2125 * Table/Field mapping
2126 *
2127 **************************************/
2128
2129 /**
2130 * Checks if mapping is needed for a table(list)
2131 *
2132 * @param string List of tables in query
2133 * @param boolean If true, it will check only if FIELDs are configured and ignore the mapped table name if any.
2134 * @return mixed Returns an array of table names (parsed version of input table) if mapping is needed, otherwise just false.
2135 */
2136 function map_needMapping($tableList,$fieldMappingOnly=FALSE) {
2137
2138 $key = $tableList.'|'.$fieldMappingOnly;
2139 if (!isset($this->cache_mappingFromTableList[$key])) {
2140 $this->cache_mappingFromTableList[$key] = FALSE; // Default:
2141
2142 $tables = $this->SQLparser->parseFromTables($tableList);
2143 if (is_array($tables)) {
2144 foreach($tables as $tableCfg) {
2145 if ($fieldMappingOnly) {
2146 if (is_array($this->mapping[$tableCfg['table']]['mapFieldNames'])) {
2147 $this->cache_mappingFromTableList[$key] = $tables;
2148 }
2149 } else {
2150 if (is_array($this->mapping[$tableCfg['table']])) {
2151 $this->cache_mappingFromTableList[$key] = $tables;
2152 }
2153 }
2154 }
2155 }
2156 }
2157
2158 return $this->cache_mappingFromTableList[$key];
2159 }
2160
2161 /**
2162 * Takes an associated array with field => value pairs and remaps the field names if configured for this table in $this->mapping array.
2163 * Be careful not to map a field name to another existing fields name (although you can use this to swap fieldnames of course...:-)
2164 * Observe mapping problems with join-results (more than one table): Joined queries should always prefix the table name to avoid problems with this.
2165 * Observe that alias fields are not mapped of course (should not be a problem though)
2166 *
2167 * @param array Input array, associative keys
2168 * @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!
2169 * @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!)
2170 * @return array Output array, with mapped associative keys.
2171 */
2172 function map_assocArray($input,$tables,$rev=FALSE) {
2173
2174 // Traverse tables from query (hopefully only one table):
2175 foreach($tables as $tableCfg) {
2176 if (is_array($this->mapping[$tableCfg['table']]['mapFieldNames'])) {
2177
2178 // Get the map (reversed if needed):
2179 if ($rev) {
2180 $theMap = array_flip($this->mapping[$tableCfg['table']]['mapFieldNames']);
2181 } else {
2182 $theMap = $this->mapping[$tableCfg['table']]['mapFieldNames'];
2183 }
2184
2185 // Traverse selected record, map fieldnames:
2186 $output = array();
2187 foreach($input as $fN => $value) {
2188
2189 // Set the field name, change it if found in mapping array:
2190 if ($theMap[$fN]) {
2191 $newKey = $theMap[$fN];
2192 } else {
2193 $newKey = $fN;
2194 }
2195
2196 // Set value to fieldname:
2197 $output[$newKey] = $value;
2198 }
2199
2200 // When done, override the $input array with the result:
2201 $input = $output;
2202 }
2203 }
2204
2205 // Return input array (which might have been altered in the mean time)
2206 return $input;
2207 }
2208
2209 /**
2210 * Remaps table/field names in a SELECT query's parts
2211 * Notice: All arguments are passed by reference!
2212 *
2213 * @param string List of fields to select from the table. This is what comes right after "SELECT ...". Required value.
2214 * @param string Table(s) from which to select. This is what comes right after "FROM ...". Require value.
2215 * @param string Where clause. This is what comes right after "WHERE ...". Can be blank.
2216 * @param string Group by field(s)
2217 * @param string Order by field(s)
2218 * @return void
2219 * @see exec_SELECTquery()
2220 */
2221 function map_remapSELECTQueryParts(&$select_fields,&$from_table,&$where_clause,&$groupBy,&$orderBy) {
2222
2223 // Tables:
2224 $tables = $this->SQLparser->parseFromTables($from_table);
2225 $defaultTable = $tables[0]['table'];
2226 foreach($tables as $k => $v) {
2227 if ($this->mapping[$v['table']]['mapTableName']) {
2228 $tables[$k]['table'] = $this->mapping[$v['table']]['mapTableName'];
2229 }
2230 }
2231 $from_table = $this->SQLparser->compileFromTables($tables);
2232
2233 // Where clause:
2234 $whereParts = $this->SQLparser->parseWhereClause($where_clause);
2235 $this->map_sqlParts($whereParts,$defaultTable);
2236 $where_clause = $this->SQLparser->compileWhereClause($whereParts);
2237
2238 // Select fields:
2239 $expFields = $this->SQLparser->parseFieldList($select_fields);
2240 $this->map_sqlParts($expFields,$defaultTable);
2241 $select_fields = $this->SQLparser->compileFieldList($expFields);
2242
2243 // Group By fields
2244 $expFields = $this->SQLparser->parseFieldList($groupBy);
2245 $this->map_sqlParts($expFields,$defaultTable);
2246 $groupBy = $this->SQLparser->compileFieldList($expFields);
2247
2248 // Order By fields
2249 $expFields = $this->SQLparser->parseFieldList($orderBy);
2250 $this->map_sqlParts($expFields,$defaultTable);
2251 $orderBy = $this->SQLparser->compileFieldList($expFields);
2252 }
2253
2254 /**
2255 * Generic mapping of table/field names arrays (as parsed by t3lib_sqlengine)
2256 *
2257 * @param array Array with parsed SQL parts; Takes both fields, tables, where-parts, group and order-by. Passed by reference.
2258 * @param string Default table name to assume if no table is found in $sqlPartArray
2259 * @return void
2260 * @access private
2261 * @see map_remapSELECTQueryParts()
2262 */
2263 function map_sqlParts(&$sqlPartArray, $defaultTable) {
2264
2265 // Traverse sql Part array:
2266 if (is_array($sqlPartArray)) {
2267 foreach($sqlPartArray as $k => $v) {
2268
2269 // Look for sublevel (WHERE parts only)
2270 if (is_array($sqlPartArray[$k]['sub'])) {
2271 $this->map_sqlParts($sqlPartArray[$k]['sub'], $defaultTable); // Call recursively!
2272 } else {
2273 // For the field, look for table mapping (generic):
2274 $t = $sqlPartArray[$k]['table'] ? $sqlPartArray[$k]['table'] : $defaultTable;
2275
2276 // Mapping field name, if set:
2277 if (is_array($this->mapping[$t]['mapFieldNames']) && $this->mapping[$t]['mapFieldNames'][$sqlPartArray[$k]['field']]) {
2278 $sqlPartArray[$k]['field'] = $this->mapping[$t]['mapFieldNames'][$sqlPartArray[$k]['field']];
2279 }
2280
2281 // Map table?
2282 if ($sqlPartArray[$k]['table'] && $this->mapping[$sqlPartArray[$k]['table']]['mapTableName']) {
2283 $sqlPartArray[$k]['table'] = $this->mapping[$sqlPartArray[$k]['table']]['mapTableName'];
2284 }
2285 }
2286 }
2287 }
2288 }
2289
2290 /**
2291 * Will do table/field mapping on a general t3lib_sqlengine-compliant SQL query
2292 * (May still not support all query types...)
2293 *
2294 * @param array Parsed QUERY as from t3lib_sqlengine::parseSQL(). NOTICE: Passed by reference!
2295 * @return void
2296 * @see t3lib_sqlengine::parseSQL()
2297 */
2298 function map_genericQueryParsed(&$parsedQuery) {
2299
2300 // Getting table - same for all:
2301 $table = $parsedQuery['TABLE'];
2302 if ($table) {
2303 // Do field mapping if needed:
2304 if ($tableArray = $this->map_needMapping($table)) {
2305
2306 // Table name:
2307 if ($this->mapping[$table]['mapTableName']) {
2308 $parsedQuery['TABLE'] = $this->mapping[$table]['mapTableName'];
2309 }
2310
2311 // Based on type, do additional changes:
2312 switch($parsedQuery['type']) {
2313 case 'ALTERTABLE':
2314
2315 // Changing field name:
2316 $newFieldName = $this->mapping[$table]['mapFieldNames'][$parsedQuery['FIELD']];
2317 if ($newFieldName) {
2318 if ($parsedQuery['FIELD'] == $parsedQuery['newField']) {
2319 $parsedQuery['FIELD'] = $parsedQuery['newField'] = $newFieldName;
2320 } else $parsedQuery['FIELD'] = $newFieldName;
2321 }
2322
2323 // Changing key field names:
2324 if (is_array($parsedQuery['fields'])) {
2325 $this->map_fieldNamesInArray($table,$parsedQuery['fields']);
2326 }
2327 break;
2328 case 'CREATETABLE':
2329 // Remapping fields:
2330 if (is_array($parsedQuery['FIELDS'])) {
2331 $newFieldsArray = array();
2332 foreach($parsedQuery['FIELDS'] as $fN => $fInfo) {
2333 if ($this->mapping[$table]['mapFieldNames'][$fN]) {
2334 $fN = $this->mapping[$table]['mapFieldNames'][$fN];
2335 }
2336 $newFieldsArray[$fN] = $fInfo;
2337 }
2338 $parsedQuery['FIELDS'] = $newFieldsArray;
2339 }
2340
2341 // Remapping keys:
2342 if (is_array($parsedQuery['KEYS'])) {
2343 foreach($parsedQuery['KEYS'] as $kN => $kInfo) {
2344 $this->map_fieldNamesInArray($table,$parsedQuery['KEYS'][$kN]);
2345 }
2346 }
2347 break;
2348
2349 /// ... and here support for all other query types should be!
2350
2351 }
2352 }
2353 } else die('ERROR, mapping: No table found in parsed Query array...');
2354 }
2355
2356 /**
2357 * Re-mapping field names in array
2358 *
2359 * @param string (TYPO3) Table name for fields.
2360 * @param array Array of fieldnames to remap. Notice: Passed by reference!
2361 * @return void
2362 */
2363 function map_fieldNamesInArray($table,&$fieldArray) {
2364 if (is_array($this->mapping[$table]['mapFieldNames'])) {
2365 foreach($fieldArray as $k => $v) {
2366 if ($this->mapping[$table]['mapFieldNames'][$v]) {
2367 $fieldArray[$k] = $this->mapping[$table]['mapFieldNames'][$v];
2368 }
2369 }
2370 }
2371 }
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389 /**************************************
2390 *
2391 * Debugging
2392 *
2393 **************************************/
2394
2395 /**
2396 * Debug handler for query execution
2397 *
2398 * @param string Function name from which this function is called.
2399 * @param string Execution time in ms of the query
2400 * @param array In-data of various kinds.
2401 * @return void
2402 * @access private
2403 */
2404 function debugHandler($function,$execTime,$inData) {
2405 // we don't want to log our own log/debug SQL
2406 $script = substr(PATH_thisScript,strlen(PATH_site));
2407
2408 if (substr($script,-strlen('dbal/mod1/index.php'))!='dbal/mod1/index.php' &&
2409 !strstr($inData['args'][0], 'tx_dbal_debuglog')) {
2410 $data = array();
2411 $errorFlag = 0;
2412 $joinTable = '';
2413
2414 if ($this->sql_error()) {
2415 $data['sqlError'] = $this->sql_error();
2416 $errorFlag|=1;
2417 }
2418
2419 // if lastQuery is empty (for whatever reason) at least log inData.args
2420 if(empty($this->lastQuery))
2421 $query = implode(' ',$inData['args']);
2422 else
2423 $query = $this->lastQuery;
2424
2425 switch($function) {
2426 case 'exec_INSERTquery':
2427 case 'exec_UPDATEquery':
2428 case 'exec_DELETEquery':
2429 $this->debug_log($query,$execTime,$data,$joinTable,$errorFlag, $script);
2430 break;
2431
2432 case 'exec_SELECTquery':
2433 // Get explain data:
2434 if ($this->conf['debugOptions']['EXPLAIN'] && t3lib_div::inList('adodb,native',$inData['handlerType'])) {
2435 $data['EXPLAIN'] = $this->debug_explain($this->lastQuery);
2436 }
2437
2438 // Check parsing of Query:
2439 if ($this->conf['debugOptions']['parseQuery']) {
2440 $parseResults = array();
2441 $parseResults['SELECT'] = $this->SQLparser->debug_parseSQLpart('SELECT',$inData['args'][1]);
2442 $parseResults['FROM'] = $this->SQLparser->debug_parseSQLpart('FROM',$inData['args'][0]);
2443 $parseResults['WHERE'] = $this->SQLparser->debug_parseSQLpart('WHERE',$inData['args'][2]);
2444 $parseResults['GROUPBY'] = $this->SQLparser->debug_parseSQLpart('SELECT',$inData['args'][3]); // Using select field list syntax
2445 $parseResults['ORDERBY'] = $this->SQLparser->debug_parseSQLpart('SELECT',$inData['args'][4]); // Using select field list syntax
2446
2447 foreach($parseResults as $k => $v) {
2448 if (!strlen($parseResults[$k])) unset($parseResults[$k]);
2449 }
2450 if (count($parseResults)) {
2451 $data['parseError'] = $parseResults;
2452 $errorFlag|=2;
2453 }
2454 }
2455
2456 // Checking joinTables:
2457 if ($this->conf['debugOptions']['joinTables']) {
2458 if (count(explode(',', $inData['ORIG_from_table']))>1) {
2459 $joinTable = $inData['args'][0];
2460 }
2461 }
2462
2463 // Logging it:
2464 $this->debug_log($query,$execTime,$data,$joinTable,$errorFlag, $script);
2465 if(!empty($inData['args'][2]))
2466 $this->debug_WHERE($inData['args'][0], $inData['args'][2], $script);
2467 break;
2468 }
2469 }
2470 }
2471
2472 /**
2473 * Log the where clause for debugging purposes.
2474 *
2475 * @param string $table Table name(s) the query was targeted at
2476 * @param string $where The WHERE clause to be logged
2477 * @param string $script The script calling the logging
2478 * @return void
2479 */
2480 function debug_WHERE($table,$where, $script='') {
2481 $insertArray = array (
2482 'tstamp' => $GLOBALS['EXEC_TIME'],
2483 'beuser_id' => intval($GLOBALS['BE_USER']->user['uid']),
2484 'script' => $script,
2485 'tablename' => $table,
2486 'whereclause' => $where
2487 );
2488
2489 $this->exec_INSERTquery('tx_dbal_debuglog_where', $insertArray);
2490 }
2491
2492 /**
2493 * Insert row in the log table
2494 *
2495 * @param string The current query
2496 * @param integer Execution time of query in milliseconds
2497 * @param array Data to be stored serialized.
2498 * @param string Join string if there IS a join.
2499 * @param integer Error status.
2500 * @param string $script The script calling the logging
2501 * @return void
2502 */
2503 function debug_log($query,$ms,$data,$join,$errorFlag, $script='') {
2504 $insertArray = array (
2505 'tstamp' => $GLOBALS['EXEC_TIME'],
2506 'beuser_id' => intval($GLOBALS['BE_USER']->user['uid']),
2507 'script' => $script,
2508 'exec_time' => $ms,
2509 'table_join' => $join,
2510 'serdata' => serialize($data),
2511 'query' => (is_array($query) ? $query[0].' WITH '.count($query[1]).' BLOB FIELDS: '.implode(', ',array_keys($query[1])) : $query),
2512 'errorFlag' => $errorFlag
2513 );
2514
2515 $this->exec_INSERTquery('tx_dbal_debuglog', $insertArray);
2516 }
2517
2518 /**
2519 * Perform EXPLAIN query on DEFAULT handler!
2520 *
2521 * @param string SELECT Query
2522 * @return array The Explain result rows in an array
2523 * @todo Not supporting other than the default handler? And what about DBMS of other kinds than MySQL - support for EXPLAIN?
2524 */
2525 function debug_explain($query) {
2526 $res = $this->sql_query('EXPLAIN '.$query);
2527
2528 $output = array();
2529 while($row = $this->sql_fetch_assoc($res)) {
2530 $output[] = $row;
2531 }
2532 return $output;
2533 }
2534 }
2535
2536
2537 if (defined('TYPO3_MODE') && $TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['ext/dbal/class.ux_t3lib_db.php']) {
2538 include_once($TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['ext/dbal/class.ux_t3lib_db.php']);
2539 }
2540 ?>