Update of DBAL sysext to 0.9.9
[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 if($this->lastParsedAndMappedQueryArray['type']=='INSERT') {
1914 return mysql_query($compiledQuery, $this->link);
1915 }
1916 return mysql_query($compiledQuery[0], $this->link);
1917 break;
1918 case 'adodb':
1919 // Compiling query:
1920 $compiledQuery = $this->SQLparser->compileSQL($this->lastParsedAndMappedQueryArray);
1921 if($this->lastParsedAndMappedQueryArray['type']=='INSERT') {
1922 return $this->exec_INSERTquery($this->lastParsedAndMappedQueryArray['TABLE'],$compiledQuery);
1923 }
1924 return $this->handlerInstance[$this->lastHandlerKey]->DataDictionary->ExecuteSQLArray($compiledQuery);
1925 break;
1926 case 'userdefined':
1927 // Compiling query:
1928 $compiledQuery = $this->SQLparser->compileSQL($this->lastParsedAndMappedQueryArray);
1929
1930 return $this->handlerInstance[$this->lastHandlerKey]->admin_query($compiledQuery);
1931 break;
1932 }
1933 } else die('ERROR: Query could not be parsed: "'.htmlspecialchars($parsedQuery).'". Query: "'.htmlspecialchars($query).'"');
1934 }
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945 /************************************
1946 *
1947 * Handler management
1948 *
1949 **************************************/
1950
1951 /**
1952 * Return the handler key pointing to an appropriate database handler as found in $this->handlerCfg array
1953 * 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!)
1954 *
1955 * @param string Table list, eg. "pages" or "pages, tt_content" or "pages AS A, tt_content AS B"
1956 * @return string Handler key (see $this->handlerCfg array) for table
1957 */
1958 function handler_getFromTableList($tableList) {
1959
1960 $key = $tableList;
1961
1962 if (!isset($this->cache_handlerKeyFromTableList[$key])) {
1963
1964 // Get tables separated:
1965 $_tableList = $tableList;
1966 $tableArray = $this->SQLparser->parseFromTables($_tableList);
1967
1968 // If success, traverse the tables:
1969 if (is_array($tableArray) && count($tableArray)) {
1970 foreach($tableArray as $vArray) {
1971
1972 // Find handler key, select "_DEFAULT" if none is specifically configured:
1973 $handlerKey = $this->table2handlerKeys[$vArray['table']] ? $this->table2handlerKeys[$vArray['table']] : '_DEFAULT';
1974
1975 // In case of separate handler keys for joined tables:
1976 if ($outputHandlerKey && $handlerKey != $outputHandlerKey) {
1977 die('DBAL fatal error: Tables in this list "'.$tableList.'" didn\'t use the same DB handler!');
1978 }
1979
1980 $outputHandlerKey = $handlerKey;
1981 }
1982
1983 // Check initialized state; if handler is NOT initialized (connected) then we will connect it!
1984 if (!isset($this->handlerInstance[$outputHandlerKey])) {
1985 $this->handler_init($outputHandlerKey);
1986 }
1987
1988 // Return handler key:
1989 $this->cache_handlerKeyFromTableList[$key] = $outputHandlerKey;
1990 } else {
1991 die('DBAL fatal error: No handler found in handler_getFromTableList() for: "'.$tableList.'" ('.$tableArray.')');
1992 }
1993 }
1994
1995 return $this->cache_handlerKeyFromTableList[$key];
1996 }
1997
1998 /**
1999 * Initialize handler (connecting to database)
2000 *
2001 * @param string Handler key
2002 * @return boolean If connection went well, return true
2003 * @see handler_getFromTableList()
2004 */
2005 function handler_init($handlerKey) {
2006
2007 // Find handler configuration:
2008 $cfgArray = $this->handlerCfg[$handlerKey];
2009 $handlerType = (string)$cfgArray['type'];
2010 $output = FALSE;
2011
2012 if (is_array($cfgArray)) {
2013 switch($handlerType) {
2014 case 'native':
2015 if ($GLOBALS['TYPO3_CONF_VARS']['SYS']['no_pconnect']) {
2016 $link = mysql_connect($cfgArray['config']['host'].(isset($cfgArray['config']['port']) ? ':'.$cfgArray['config']['port'] : ''), $cfgArray['config']['username'], $cfgArray['config']['password'], true);
2017 } else {
2018 $link = mysql_pconnect($cfgArray['config']['host'].(isset($cfgArray['config']['port']) ? ':'.$cfgArray['config']['port'] : ''), $cfgArray['config']['username'], $cfgArray['config']['password']);
2019 }
2020
2021 // Set handler instance:
2022 $this->handlerInstance[$handlerKey] = array('handlerType' => 'native', 'link' => $link);
2023
2024 // If link succeeded:
2025 if ($link) {
2026 // For default, set ->link (see t3lib_DB)
2027 if ($handlerKey == '_DEFAULT') {
2028 $this->link = $link;
2029 }
2030
2031 // Select database as well:
2032 if (mysql_select_db($cfgArray['config']['database'], $link)) {
2033 $output = TRUE;
2034 }
2035 $setDBinit = t3lib_div::trimExplode(chr(10), $GLOBALS['TYPO3_CONF_VARS']['SYS']['setDBinit'], 1);
2036 foreach ($setDBinit as $v) {
2037 if (mysql_query($v, $this->link) === FALSE) {
2038 t3lib_div::sysLog('Could not initialize DB connection with query "'.$v.'".','Core',3);
2039 }
2040 }
2041 } else {
2042 t3lib_div::sysLog('Could not connect to MySQL server '.$cfgArray['config']['host'].' with user '.$cfgArray['config']['username'].'.','Core',4);
2043 }
2044 break;
2045 case 'adodb':
2046 $output = true;
2047 require_once(t3lib_extMgm::extPath('adodb').'adodb/adodb.inc.php');
2048 if(!defined('ADODB_FORCE_NULLS')) define('ADODB_FORCE_NULLS', 1);
2049 $GLOBALS['ADODB_FORCE_TYPE'] = ADODB_FORCE_VALUE;
2050 $GLOBALS['ADODB_FETCH_MODE'] = ADODB_FETCH_BOTH;
2051
2052 $this->handlerInstance[$handlerKey] = &ADONewConnection($cfgArray['config']['driver']);
2053 if ($GLOBALS['TYPO3_CONF_VARS']['SYS']['no_pconnect']) {
2054 $this->handlerInstance[$handlerKey]->Connect($cfgArray['config']['host'].(isset($cfgArray['config']['port']) ? ':'.$cfgArray['config']['port'] : ''),$cfgArray['config']['username'],$cfgArray['config']['password'],$cfgArray['config']['database']);
2055 } else {
2056 $this->handlerInstance[$handlerKey]->PConnect($cfgArray['config']['host'].(isset($cfgArray['config']['port']) ? ':'.$cfgArray['config']['port'] : ''),$cfgArray['config']['username'],$cfgArray['config']['password'],$cfgArray['config']['database']);
2057 }
2058 if(!$this->handlerInstance[$handlerKey]->isConnected()) {
2059 $dsn = $cfgArray['config']['driver'].'://'.$cfgArray['config']['username'].
2060 (strlen($cfgArray['config']['password']) ? ':XXXX@' : '').
2061 $cfgArray['config']['host'].(isset($cfgArray['config']['port']) ? ':'.$cfgArray['config']['port'] : '').'/'.$cfgArray['config']['database'].
2062 ($GLOBALS['TYPO3_CONF_VARS']['SYS']['no_pconnect'] ? '' : '?persistent=1');
2063 t3lib_div::sysLog('Could not connect to DB server using ADOdb on '.$cfgArray['config']['host'].' with user '.$cfgArray['config']['username'].'.','Core',4);
2064 error_log('DBAL error: Connection to '.$dsn.' failed. Maybe PHP doesn\'t support the database?');
2065 $output = false;
2066 } else {
2067 $this->handlerInstance[$handlerKey]->DataDictionary = NewDataDictionary($this->handlerInstance[$handlerKey]);
2068 $this->handlerInstance[$handlerKey]->last_insert_id = 0;
2069 if(isset($cfgArray['config']['sequenceStart'])) {
2070 $this->handlerInstance[$handlerKey]->sequenceStart = $cfgArray['config']['sequenceStart'];
2071 } else {
2072 $this->handlerInstance[$handlerKey]->sequenceStart = 1;
2073 }
2074 }
2075 break;
2076 case 'userdefined':
2077 // Find class file:
2078 $fileName = t3lib_div::getFileAbsFileName($cfgArray['config']['classFile']);
2079 if (@is_file($fileName)) {
2080 require_once($fileName);
2081 } else die('DBAL error: "'.$fileName.'" was not a file to include.');
2082
2083 // Initialize:
2084 $this->handlerInstance[$handlerKey] = t3lib_div::makeInstance($cfgArray['config']['class']);
2085 $this->handlerInstance[$handlerKey]->init($cfgArray,$this);
2086
2087 if (is_object($this->handlerInstance[$handlerKey])) {
2088 $output = TRUE;
2089 }
2090 break;
2091 default:
2092 die('ERROR: Invalid handler type: "'.$cfgArray['type'].'"');
2093 break;
2094 }
2095
2096 return $output;
2097 } else die('ERROR: No handler for key "'.$handlerKey.'"');
2098 }
2099
2100
2101 /**
2102 * Checks whether the DBAL is currently inside an operation running on the "native" DB handler (i.e. MySQL)
2103 *
2104 * @return boolean True if running on "native" DB handler (i.e. MySQL)
2105 */
2106 function runningNative() {
2107 return ((string)$this->handlerCfg[$this->lastHandlerKey]['type']==='native');
2108 }
2109
2110
2111 /**
2112 * Checks whether the ADOdb handler is running with a driver that contains the argument
2113 *
2114 * @param string $driver Driver name, matched with strstr().
2115 * @return boolean True if running with the given driver
2116 */
2117 function runningADOdbDriver($driver) {
2118 return strstr($this->handlerCfg[$this->lastHandlerKey]['config']['driver'], $driver);
2119 }
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130 /************************************
2131 *
2132 * Table/Field mapping
2133 *
2134 **************************************/
2135
2136 /**
2137 * Checks if mapping is needed for a table(list)
2138 *
2139 * @param string List of tables in query
2140 * @param boolean If true, it will check only if FIELDs are configured and ignore the mapped table name if any.
2141 * @return mixed Returns an array of table names (parsed version of input table) if mapping is needed, otherwise just false.
2142 */
2143 function map_needMapping($tableList,$fieldMappingOnly=FALSE) {
2144
2145 $key = $tableList.'|'.$fieldMappingOnly;
2146 if (!isset($this->cache_mappingFromTableList[$key])) {
2147 $this->cache_mappingFromTableList[$key] = FALSE; // Default:
2148
2149 $tables = $this->SQLparser->parseFromTables($tableList);
2150 if (is_array($tables)) {
2151 foreach($tables as $tableCfg) {
2152 if ($fieldMappingOnly) {
2153 if (is_array($this->mapping[$tableCfg['table']]['mapFieldNames'])) {
2154 $this->cache_mappingFromTableList[$key] = $tables;
2155 }
2156 } else {
2157 if (is_array($this->mapping[$tableCfg['table']])) {
2158 $this->cache_mappingFromTableList[$key] = $tables;
2159 }
2160 }
2161 }
2162 }
2163 }
2164
2165 return $this->cache_mappingFromTableList[$key];
2166 }
2167
2168 /**
2169 * Takes an associated array with field => value pairs and remaps the field names if configured for this table in $this->mapping array.
2170 * Be careful not to map a field name to another existing fields name (although you can use this to swap fieldnames of course...:-)
2171 * Observe mapping problems with join-results (more than one table): Joined queries should always prefix the table name to avoid problems with this.
2172 * Observe that alias fields are not mapped of course (should not be a problem though)
2173 *
2174 * @param array Input array, associative keys
2175 * @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!
2176 * @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!)
2177 * @return array Output array, with mapped associative keys.
2178 */
2179 function map_assocArray($input,$tables,$rev=FALSE) {
2180
2181 // Traverse tables from query (hopefully only one table):
2182 foreach($tables as $tableCfg) {
2183 if (is_array($this->mapping[$tableCfg['table']]['mapFieldNames'])) {
2184
2185 // Get the map (reversed if needed):
2186 if ($rev) {
2187 $theMap = array_flip($this->mapping[$tableCfg['table']]['mapFieldNames']);
2188 } else {
2189 $theMap = $this->mapping[$tableCfg['table']]['mapFieldNames'];
2190 }
2191
2192 // Traverse selected record, map fieldnames:
2193 $output = array();
2194 foreach($input as $fN => $value) {
2195
2196 // Set the field name, change it if found in mapping array:
2197 if ($theMap[$fN]) {
2198 $newKey = $theMap[$fN];
2199 } else {
2200 $newKey = $fN;
2201 }
2202
2203 // Set value to fieldname:
2204 $output[$newKey] = $value;
2205 }
2206
2207 // When done, override the $input array with the result:
2208 $input = $output;
2209 }
2210 }
2211
2212 // Return input array (which might have been altered in the mean time)
2213 return $input;
2214 }
2215
2216 /**
2217 * Remaps table/field names in a SELECT query's parts
2218 * Notice: All arguments are passed by reference!
2219 *
2220 * @param string List of fields to select from the table. This is what comes right after "SELECT ...". Required value.
2221 * @param string Table(s) from which to select. This is what comes right after "FROM ...". Require value.
2222 * @param string Where clause. This is what comes right after "WHERE ...". Can be blank.
2223 * @param string Group by field(s)
2224 * @param string Order by field(s)
2225 * @return void
2226 * @see exec_SELECTquery()
2227 */
2228 function map_remapSELECTQueryParts(&$select_fields,&$from_table,&$where_clause,&$groupBy,&$orderBy) {
2229
2230 // Tables:
2231 $tables = $this->SQLparser->parseFromTables($from_table);
2232 $defaultTable = $tables[0]['table'];
2233 foreach($tables as $k => $v) {
2234 if ($this->mapping[$v['table']]['mapTableName']) {
2235 $tables[$k]['table'] = $this->mapping[$v['table']]['mapTableName'];
2236 }
2237 }
2238 $from_table = $this->SQLparser->compileFromTables($tables);
2239
2240 // Where clause:
2241 $whereParts = $this->SQLparser->parseWhereClause($where_clause);
2242 $this->map_sqlParts($whereParts,$defaultTable);
2243 $where_clause = $this->SQLparser->compileWhereClause($whereParts);
2244
2245 // Select fields:
2246 $expFields = $this->SQLparser->parseFieldList($select_fields);
2247 $this->map_sqlParts($expFields,$defaultTable);
2248 $select_fields = $this->SQLparser->compileFieldList($expFields);
2249
2250 // Group By fields
2251 $expFields = $this->SQLparser->parseFieldList($groupBy);
2252 $this->map_sqlParts($expFields,$defaultTable);
2253 $groupBy = $this->SQLparser->compileFieldList($expFields);
2254
2255 // Order By fields
2256 $expFields = $this->SQLparser->parseFieldList($orderBy);
2257 $this->map_sqlParts($expFields,$defaultTable);
2258 $orderBy = $this->SQLparser->compileFieldList($expFields);
2259 }
2260
2261 /**
2262 * Generic mapping of table/field names arrays (as parsed by t3lib_sqlengine)
2263 *
2264 * @param array Array with parsed SQL parts; Takes both fields, tables, where-parts, group and order-by. Passed by reference.
2265 * @param string Default table name to assume if no table is found in $sqlPartArray
2266 * @return void
2267 * @access private
2268 * @see map_remapSELECTQueryParts()
2269 */
2270 function map_sqlParts(&$sqlPartArray, $defaultTable) {
2271
2272 // Traverse sql Part array:
2273 if (is_array($sqlPartArray)) {
2274 foreach($sqlPartArray as $k => $v) {
2275
2276 // Look for sublevel (WHERE parts only)
2277 if (is_array($sqlPartArray[$k]['sub'])) {
2278 $this->map_sqlParts($sqlPartArray[$k]['sub'], $defaultTable); // Call recursively!
2279 } else {
2280 // For the field, look for table mapping (generic):
2281 $t = $sqlPartArray[$k]['table'] ? $sqlPartArray[$k]['table'] : $defaultTable;
2282
2283 // Mapping field name, if set:
2284 if (is_array($this->mapping[$t]['mapFieldNames']) && $this->mapping[$t]['mapFieldNames'][$sqlPartArray[$k]['field']]) {
2285 $sqlPartArray[$k]['field'] = $this->mapping[$t]['mapFieldNames'][$sqlPartArray[$k]['field']];
2286 }
2287
2288 // Map table?
2289 if ($sqlPartArray[$k]['table'] && $this->mapping[$sqlPartArray[$k]['table']]['mapTableName']) {
2290 $sqlPartArray[$k]['table'] = $this->mapping[$sqlPartArray[$k]['table']]['mapTableName'];
2291 }
2292 }
2293 }
2294 }
2295 }
2296
2297 /**
2298 * Will do table/field mapping on a general t3lib_sqlengine-compliant SQL query
2299 * (May still not support all query types...)
2300 *
2301 * @param array Parsed QUERY as from t3lib_sqlengine::parseSQL(). NOTICE: Passed by reference!
2302 * @return void
2303 * @see t3lib_sqlengine::parseSQL()
2304 */
2305 function map_genericQueryParsed(&$parsedQuery) {
2306
2307 // Getting table - same for all:
2308 $table = $parsedQuery['TABLE'];
2309 if ($table) {
2310 // Do field mapping if needed:
2311 if ($tableArray = $this->map_needMapping($table)) {
2312
2313 // Table name:
2314 if ($this->mapping[$table]['mapTableName']) {
2315 $parsedQuery['TABLE'] = $this->mapping[$table]['mapTableName'];
2316 }
2317
2318 // Based on type, do additional changes:
2319 switch($parsedQuery['type']) {
2320 case 'ALTERTABLE':
2321
2322 // Changing field name:
2323 $newFieldName = $this->mapping[$table]['mapFieldNames'][$parsedQuery['FIELD']];
2324 if ($newFieldName) {
2325 if ($parsedQuery['FIELD'] == $parsedQuery['newField']) {
2326 $parsedQuery['FIELD'] = $parsedQuery['newField'] = $newFieldName;
2327 } else $parsedQuery['FIELD'] = $newFieldName;
2328 }
2329
2330 // Changing key field names:
2331 if (is_array($parsedQuery['fields'])) {
2332 $this->map_fieldNamesInArray($table,$parsedQuery['fields']);
2333 }
2334 break;
2335 case 'CREATETABLE':
2336 // Remapping fields:
2337 if (is_array($parsedQuery['FIELDS'])) {
2338 $newFieldsArray = array();
2339 foreach($parsedQuery['FIELDS'] as $fN => $fInfo) {
2340 if ($this->mapping[$table]['mapFieldNames'][$fN]) {
2341 $fN = $this->mapping[$table]['mapFieldNames'][$fN];
2342 }
2343 $newFieldsArray[$fN] = $fInfo;
2344 }
2345 $parsedQuery['FIELDS'] = $newFieldsArray;
2346 }
2347
2348 // Remapping keys:
2349 if (is_array($parsedQuery['KEYS'])) {
2350 foreach($parsedQuery['KEYS'] as $kN => $kInfo) {
2351 $this->map_fieldNamesInArray($table,$parsedQuery['KEYS'][$kN]);
2352 }
2353 }
2354 break;
2355
2356 /// ... and here support for all other query types should be!
2357
2358 }
2359 }
2360 } else die('ERROR, mapping: No table found in parsed Query array...');
2361 }
2362
2363 /**
2364 * Re-mapping field names in array
2365 *
2366 * @param string (TYPO3) Table name for fields.
2367 * @param array Array of fieldnames to remap. Notice: Passed by reference!
2368 * @return void
2369 */
2370 function map_fieldNamesInArray($table,&$fieldArray) {
2371 if (is_array($this->mapping[$table]['mapFieldNames'])) {
2372 foreach($fieldArray as $k => $v) {
2373 if ($this->mapping[$table]['mapFieldNames'][$v]) {
2374 $fieldArray[$k] = $this->mapping[$table]['mapFieldNames'][$v];
2375 }
2376 }
2377 }
2378 }
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
2396 /**************************************
2397 *
2398 * Debugging
2399 *
2400 **************************************/
2401
2402 /**
2403 * Debug handler for query execution
2404 *
2405 * @param string Function name from which this function is called.
2406 * @param string Execution time in ms of the query
2407 * @param array In-data of various kinds.
2408 * @return void
2409 * @access private
2410 */
2411 function debugHandler($function,$execTime,$inData) {
2412 // we don't want to log our own log/debug SQL
2413 $script = substr(PATH_thisScript,strlen(PATH_site));
2414
2415 if (substr($script,-strlen('dbal/mod1/index.php'))!='dbal/mod1/index.php' &&
2416 !strstr($inData['args'][0], 'tx_dbal_debuglog')) {
2417 $data = array();
2418 $errorFlag = 0;
2419 $joinTable = '';
2420
2421 if ($this->sql_error()) {
2422 $data['sqlError'] = $this->sql_error();
2423 $errorFlag|=1;
2424 }
2425
2426 // if lastQuery is empty (for whatever reason) at least log inData.args
2427 if(empty($this->lastQuery))
2428 $query = implode(' ',$inData['args']);
2429 else
2430 $query = $this->lastQuery;
2431
2432 switch($function) {
2433 case 'exec_INSERTquery':
2434 case 'exec_UPDATEquery':
2435 case 'exec_DELETEquery':
2436 $this->debug_log($query,$execTime,$data,$joinTable,$errorFlag, $script);
2437 break;
2438
2439 case 'exec_SELECTquery':
2440 // Get explain data:
2441 if ($this->conf['debugOptions']['EXPLAIN'] && t3lib_div::inList('adodb,native',$inData['handlerType'])) {
2442 $data['EXPLAIN'] = $this->debug_explain($this->lastQuery);
2443 }
2444
2445 // Check parsing of Query:
2446 if ($this->conf['debugOptions']['parseQuery']) {
2447 $parseResults = array();
2448 $parseResults['SELECT'] = $this->SQLparser->debug_parseSQLpart('SELECT',$inData['args'][1]);
2449 $parseResults['FROM'] = $this->SQLparser->debug_parseSQLpart('FROM',$inData['args'][0]);
2450 $parseResults['WHERE'] = $this->SQLparser->debug_parseSQLpart('WHERE',$inData['args'][2]);
2451 $parseResults['GROUPBY'] = $this->SQLparser->debug_parseSQLpart('SELECT',$inData['args'][3]); // Using select field list syntax
2452 $parseResults['ORDERBY'] = $this->SQLparser->debug_parseSQLpart('SELECT',$inData['args'][4]); // Using select field list syntax
2453
2454 foreach($parseResults as $k => $v) {
2455 if (!strlen($parseResults[$k])) unset($parseResults[$k]);
2456 }
2457 if (count($parseResults)) {
2458 $data['parseError'] = $parseResults;
2459 $errorFlag|=2;
2460 }
2461 }
2462
2463 // Checking joinTables:
2464 if ($this->conf['debugOptions']['joinTables']) {
2465 if (count(explode(',', $inData['ORIG_from_table']))>1) {
2466 $joinTable = $inData['args'][0];
2467 }
2468 }
2469
2470 // Logging it:
2471 $this->debug_log($query,$execTime,$data,$joinTable,$errorFlag, $script);
2472 if(!empty($inData['args'][2]))
2473 $this->debug_WHERE($inData['args'][0], $inData['args'][2], $script);
2474 break;
2475 }
2476 }
2477 }
2478
2479 /**
2480 * Log the where clause for debugging purposes.
2481 *
2482 * @param string $table Table name(s) the query was targeted at
2483 * @param string $where The WHERE clause to be logged
2484 * @param string $script The script calling the logging
2485 * @return void
2486 */
2487 function debug_WHERE($table,$where, $script='') {
2488 $insertArray = array (
2489 'tstamp' => $GLOBALS['EXEC_TIME'],
2490 'beuser_id' => intval($GLOBALS['BE_USER']->user['uid']),
2491 'script' => $script,
2492 'tablename' => $table,
2493 'whereclause' => $where
2494 );
2495
2496 $this->exec_INSERTquery('tx_dbal_debuglog_where', $insertArray);
2497 }
2498
2499 /**
2500 * Insert row in the log table
2501 *
2502 * @param string The current query
2503 * @param integer Execution time of query in milliseconds
2504 * @param array Data to be stored serialized.
2505 * @param string Join string if there IS a join.
2506 * @param integer Error status.
2507 * @param string $script The script calling the logging
2508 * @return void
2509 */
2510 function debug_log($query,$ms,$data,$join,$errorFlag, $script='') {
2511 $insertArray = array (
2512 'tstamp' => $GLOBALS['EXEC_TIME'],
2513 'beuser_id' => intval($GLOBALS['BE_USER']->user['uid']),
2514 'script' => $script,
2515 'exec_time' => $ms,
2516 'table_join' => $join,
2517 'serdata' => serialize($data),
2518 'query' => (is_array($query) ? $query[0].' WITH '.count($query[1]).' BLOB FIELDS: '.implode(', ',array_keys($query[1])) : $query),
2519 'errorFlag' => $errorFlag
2520 );
2521
2522 $this->exec_INSERTquery('tx_dbal_debuglog', $insertArray);
2523 }
2524
2525 /**
2526 * Perform EXPLAIN query on DEFAULT handler!
2527 *
2528 * @param string SELECT Query
2529 * @return array The Explain result rows in an array
2530 * @todo Not supporting other than the default handler? And what about DBMS of other kinds than MySQL - support for EXPLAIN?
2531 */
2532 function debug_explain($query) {
2533 $res = $this->sql_query('EXPLAIN '.$query);
2534
2535 $output = array();
2536 while($row = $this->sql_fetch_assoc($res)) {
2537 $output[] = $row;
2538 }
2539 return $output;
2540 }
2541 }
2542
2543
2544 if (defined('TYPO3_MODE') && $TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['ext/dbal/class.ux_t3lib_db.php']) {
2545 include_once($TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['ext/dbal/class.ux_t3lib_db.php']);
2546 }
2547 ?>