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