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