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