Fixed bug #6196: IFNULL operator cannot be parsed
[Packages/TYPO3.CMS.git] / typo3 / sysext / dbal / class.ux_t3lib_sqlparser.php
1 <?php
2 /***************************************************************
3 * Copyright notice
4 *
5 * (c) 2004-2009 Kasper Skaarhoj (kasperYYYY@typo3.com)
6 * (c) 2004-2009 Karsten Dambekalns <karsten@typo3.org>
7 * (c) 2009-2010 Xavier Perseguers <typo3@perseguers.ch>
8 * All rights reserved
9 *
10 * This script is part of the TYPO3 project. The TYPO3 project is
11 * free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * The GNU General Public License can be found at
17 * http://www.gnu.org/copyleft/gpl.html.
18 * A copy is found in the textfile GPL.txt and important notices to the license
19 * from the author is found in LICENSE.txt distributed with these scripts.
20 *
21 *
22 * This script is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU General Public License for more details.
26 *
27 * This copyright notice MUST APPEAR in all copies of the script!
28 ***************************************************************/
29 /**
30 * PHP SQL engine
31 *
32 * $Id$
33 *
34 * @author Kasper Skaarhoj <kasperYYYY@typo3.com>
35 * @author Karsten Dambekalns <k.dambekalns@fishfarm.de>
36 * @author Xavier Perseguers <typo3@perseguers.ch>
37 */
38
39
40 /**
41 * PHP SQL engine / server
42 *
43 * @author Kasper Skaarhoj <kasper@typo3.com>
44 * @package TYPO3
45 * @subpackage t3lib
46 */
47 class ux_t3lib_sqlparser extends t3lib_sqlparser {
48
49 /**
50 * Compiles a "SELECT [output] FROM..:" field list based on input array (made with ->parseFieldList())
51 * Can also compile field lists for ORDER BY and GROUP BY.
52 *
53 * @param array Array of select fields, (made with ->parseFieldList())
54 * @param boolean Whether comments should be compiled
55 * @param boolean Whether function mapping should take place
56 * @return string Select field string
57 * @see parseFieldList()
58 */
59 public function compileFieldList($selectFields, $compileComments = TRUE, $functionMapping = TRUE) {
60 switch ((string)$GLOBALS['TYPO3_DB']->handlerCfg[$GLOBALS['TYPO3_DB']->lastHandlerKey]['type']) {
61 case 'native':
62 $output = parent::compileFieldList($selectFields, $compileComments);
63 break;
64 case 'adodb':
65 $output = '';
66 // Traverse the selectFields if any:
67 if (is_array($selectFields)) {
68 $outputParts = array();
69 foreach ($selectFields as $k => $v) {
70
71 // Detecting type:
72 switch($v['type']) {
73 case 'function':
74 $outputParts[$k] = $v['function'] . '(' . $v['func_content'] . ')';
75 break;
76 case 'flow-control':
77 if ($v['flow-control']['type'] === 'CASE') {
78 $outputParts[$k] = $this->compileCaseStatement($v['flow-control'], $functionMapping);
79 }
80 break;
81 case 'field':
82 $outputParts[$k] = ($v['distinct'] ? $v['distinct'] : '') . ($v['table'] ? $v['table'] . '.' : '') . $v['field'];
83 break;
84 }
85
86 // Alias:
87 if ($v['as']) {
88 $outputParts[$k] .= ' ' . $v['as_keyword'] . ' ' . $v['as'];
89 }
90
91 // Specifically for ORDER BY and GROUP BY field lists:
92 if ($v['sortDir']) {
93 $outputParts[$k] .= ' ' . $v['sortDir'];
94 }
95 }
96 // TODO: Handle SQL hints in comments according to current DBMS
97 if (/* $compileComments */ FALSE && $selectFields[0]['comments']) {
98 $output = $selectFields[0]['comments'] . ' ';
99 }
100 $output .= implode(', ', $outputParts);
101 }
102 break;
103 }
104 return $output;
105 }
106
107 /**
108 * Compiles a CASE ... WHEN flow-control construct based on input array (made with ->parseCaseStatement())
109 *
110 * @param array Array of case components, (made with ->parseCaseStatement())
111 * @param boolean Whether function mapping should take place
112 * @return string case when string
113 * @see parseCaseStatement()
114 */
115 protected function compileCaseStatement(array $components, $functionMapping = TRUE) {
116 switch ((string)$GLOBALS['TYPO3_DB']->handlerCfg[$GLOBALS['TYPO3_DB']->lastHandlerKey]['type']) {
117 case 'native':
118 $output = parent::compileCaseStatement($components);
119 break;
120 case 'adodb':
121 $statement = 'CASE';
122 if (isset($components['case_field'])) {
123 $statement .= ' ' . $components['case_field'];
124 } elseif (isset($components['case_value'])) {
125 $statement .= ' ' . $components['case_value'][1] . $components['case_value'][0] . $components['case_value'][1];
126 }
127 foreach ($components['when'] as $when) {
128 $statement .= ' WHEN ';
129 $statement .= $this->compileWhereClause($when['when_value'], $functionMapping);
130 $statement .= ' THEN ';
131 $statement .= $when['then_value'][1] . $when['then_value'][0] . $when['then_value'][1];
132 }
133 if (isset($components['else'])) {
134 $statement .= ' ELSE ';
135 $statement .= $components['else'][1] . $components['else'][0] . $components['else'][1];
136 }
137 $statement .= ' END';
138 $output = $statement;
139 break;
140 }
141 return $output;
142 }
143
144 /**
145 * Add slashes function used for compiling queries
146 * This method overrides the method from t3lib_sqlparser because
147 * the input string is already properly escaped.
148 *
149 * @param string Input string
150 * @return string Output string
151 */
152 protected function compileAddslashes($str) {
153 return $str;
154 }
155
156 /*************************
157 *
158 * Compiling queries
159 *
160 *************************/
161
162 /**
163 * Compiles an INSERT statement from components array
164 *
165 * @param array Array of SQL query components
166 * @return string SQL INSERT query / array
167 * @see parseINSERT()
168 */
169 protected function compileINSERT($components) {
170 switch ((string)$GLOBALS['TYPO3_DB']->handlerCfg[$GLOBALS['TYPO3_DB']->lastHandlerKey]['type']) {
171 case 'native':
172 $query = parent::compileINSERT($components);
173 break;
174 case 'adodb':
175 $values = array();
176
177 if (isset($components['VALUES_ONLY']) && is_array($components['VALUES_ONLY'])) {
178 $valuesComponents = $components['EXTENDED'] === '1' ? $components['VALUES_ONLY'] : array($components['VALUES_ONLY']);
179 $tableFields = array_keys($GLOBALS['TYPO3_DB']->cache_fieldType[$components['TABLE']]);
180 } else {
181 $valuesComponents = $components['EXTENDED'] === '1' ? $components['FIELDS'] : array($components['FIELDS']);
182 $tableFields = array_keys($valuesComponents[0]);
183 }
184
185 foreach ($valuesComponents as $valuesComponent) {
186 $fields = array();
187 $fc = 0;
188 foreach ($valuesComponent as $fV) {
189 $fields[$tableFields[$fc++]] = $fV[0];
190 }
191 $values[] = $fields;
192 }
193 $query = count($values) === 1 ? $values[0] : $values;
194 break;
195 }
196
197 return $query;
198 }
199
200 /**
201 * Compiles a DROP TABLE statement from components array
202 *
203 * @param array Array of SQL query components
204 * @return string SQL DROP TABLE query
205 * @see compileSQL()
206 */
207 private function compileDROPTABLE($components) {
208 switch ((string)$GLOBALS['TYPO3_DB']->handlerCfg[$GLOBALS['TYPO3_DB']->lastHandlerKey]['type']) {
209 case 'native':
210 $query = 'DROP TABLE' . ($components['ifExists'] ? ' IF EXISTS' : '') . ' ' . $components['TABLE'];
211 break;
212 case 'adodb':
213 $handlerKey = $GLOBALS['TYPO3_DB']->handler_getFromTableList($components['TABLE']);
214 $tableName = $GLOBALS['TYPO3_DB']->quoteName($components['TABLE'], $handlerKey, TRUE);
215 $query = $GLOBALS['TYPO3_DB']->handlerInstance[$handlerKey]->DataDictionary->DropTableSQL($tableName);
216 break;
217 }
218
219 return $query;
220 }
221
222 /**
223 * Compiles a CREATE TABLE statement from components array
224 *
225 * @param array Array of SQL query components
226 * @return array array with SQL CREATE TABLE/INDEX command(s)
227 * @see parseCREATETABLE()
228 */
229 public function compileCREATETABLE($components) {
230 // Execute query (based on handler derived from the TABLE name which we actually know for once!)
231 switch ((string)$GLOBALS['TYPO3_DB']->handlerCfg[$GLOBALS['TYPO3_DB']->handler_getFromTableList($components['TABLE'])]['type']) {
232 case 'native':
233 $query[] = parent::compileCREATETABLE($components);
234 break;
235 case 'adodb':
236 // Create fields and keys:
237 $fieldsKeys = array();
238 $indexKeys = array();
239
240 foreach ($components['FIELDS'] as $fN => $fCfg) {
241 $handlerKey = $GLOBALS['TYPO3_DB']->handler_getFromTableList($components['TABLE']);
242 $fieldsKeys[$fN] = $GLOBALS['TYPO3_DB']->quoteName($fN, $handlerKey, TRUE) . ' ' . $this->compileFieldCfg($fCfg['definition']);
243 }
244
245 if (isset($components['KEYS']) && is_array($components['KEYS'])) {
246 foreach($components['KEYS'] as $kN => $kCfg) {
247 if ($kN === 'PRIMARYKEY') {
248 foreach ($kCfg as $n => $field) {
249 $fieldsKeys[$field] .= ' PRIMARY';
250 }
251 } elseif ($kN === 'UNIQUE') {
252 foreach ($kCfg as $n => $field) {
253 $indexKeys = array_merge($indexKeys, $GLOBALS['TYPO3_DB']->handlerInstance[$GLOBALS['TYPO3_DB']->handler_getFromTableList($components['TABLE'])]->DataDictionary->CreateIndexSQL($n, $components['TABLE'], $field, array('UNIQUE')));
254 }
255 } else {
256 $indexKeys = array_merge($indexKeys, $GLOBALS['TYPO3_DB']->handlerInstance[$GLOBALS['TYPO3_DB']->handler_getFromTableList($components['TABLE'])]->DataDictionary->CreateIndexSQL($components['TABLE'] . '_' . $kN, $components['TABLE'], $kCfg));
257 }
258 }
259 }
260
261 // Generally create without OID on PostgreSQL
262 $tableOptions = array('postgres' => 'WITHOUT OIDS');
263
264 // Fetch table/index generation query:
265 $tableName = $GLOBALS['TYPO3_DB']->quoteName($components['TABLE'], NULL, TRUE);
266 $query = array_merge($GLOBALS['TYPO3_DB']->handlerInstance[$GLOBALS['TYPO3_DB']->lastHandlerKey]->DataDictionary->CreateTableSQL($tableName, implode(',' . chr(10), $fieldsKeys), $tableOptions), $indexKeys);
267 break;
268 }
269
270 return $query;
271 }
272
273 /**
274 * Compiles an ALTER TABLE statement from components array
275 *
276 * @param array Array of SQL query components
277 * @return string SQL ALTER TABLE query
278 * @see parseALTERTABLE()
279 */
280 public function compileALTERTABLE($components) {
281 // Execute query (based on handler derived from the TABLE name which we actually know for once!)
282 switch ((string)$GLOBALS['TYPO3_DB']->handlerCfg[$GLOBALS['TYPO3_DB']->lastHandlerKey]['type']) {
283 case 'native':
284 $query[] = parent::compileALTERTABLE($components);
285 break;
286 case 'adodb':
287 $tableName = $GLOBALS['TYPO3_DB']->quoteName($components['TABLE'], NULL, TRUE);
288 $fieldName = $GLOBALS['TYPO3_DB']->quoteName($components['FIELD'], NULL, TRUE);
289 switch (strtoupper(str_replace(array(' ', "\n", "\r", "\t"), '', $components['action']))) {
290 case 'ADD':
291 $query = $GLOBALS['TYPO3_DB']->handlerInstance[$GLOBALS['TYPO3_DB']->lastHandlerKey]->DataDictionary->AddColumnSQL($tableName, $fieldName . ' ' . $this->compileFieldCfg($components['definition']));
292 break;
293 case 'CHANGE':
294 $query = $GLOBALS['TYPO3_DB']->handlerInstance[$GLOBALS['TYPO3_DB']->lastHandlerKey]->DataDictionary->AlterColumnSQL($tableName, $fieldName . ' ' . $this->compileFieldCfg($components['definition']));
295 break;
296 case 'DROP':
297 case 'DROPKEY':
298 break;
299 case 'ADDKEY':
300 case 'ADDPRIMARYKEY':
301 $query .= ' (' . implode(',', $components['fields']) . ')';
302 break;
303 }
304 break;
305 }
306
307 return $query;
308 }
309
310 /**
311 * Compile field definition
312 *
313 * @param array Field definition parts
314 * @return string Field definition string
315 */
316 public function compileFieldCfg($fieldCfg) {
317 switch ((string)$GLOBALS['TYPO3_DB']->handlerCfg[$GLOBALS['TYPO3_DB']->lastHandlerKey]['type']) {
318 case 'native':
319 $cfg = parent::compileFieldCfg($fieldCfg);
320 break;
321 case 'adodb':
322 // Set type:
323 $type = $GLOBALS['TYPO3_DB']->MySQLMetaType($fieldCfg['fieldType']);
324 $cfg = $type;
325
326 // Add value, if any:
327 if (strlen($fieldCfg['value']) && (in_array($type, array('C', 'C2')))) {
328 $cfg .= ' '.$fieldCfg['value'];
329 } elseif (!isset($fieldCfg['value']) && (in_array($type, array('C', 'C2')))) {
330 $cfg .= ' 255'; // add 255 as length for varchar without specified length (e.g. coming from tinytext, tinyblob)
331 }
332
333 // Add additional features:
334 $noQuote = TRUE;
335 if (is_array($fieldCfg['featureIndex'])) {
336
337 // MySQL assigns DEFAULT value automatically if NOT NULL, fake this here
338 // numeric fields get 0 as default, other fields an empty string
339 if (isset($fieldCfg['featureIndex']['NOTNULL']) && !isset($fieldCfg['featureIndex']['DEFAULT']) && !isset($fieldCfg['featureIndex']['AUTO_INCREMENT'])) {
340 switch ($type) {
341 case 'I8':
342 case 'F':
343 case 'N':
344 $fieldCfg['featureIndex']['DEFAULT'] = array('keyword' => 'DEFAULT', 'value' => array('0', ''));
345 break;
346 default:
347 $fieldCfg['featureIndex']['DEFAULT'] = array('keyword' => 'DEFAULT', 'value' => array('', '\''));
348 }
349 }
350
351 foreach ($fieldCfg['featureIndex'] as $feature => $featureDef) {
352 switch (TRUE) {
353 // unsigned only for mysql, as it is mysql specific
354 case ($feature === 'UNSIGNED' && !$GLOBALS['TYPO3_DB']->runningADOdbDriver('mysql')):
355 // auto_increment is removed, it is handled by (emulated) sequences
356 case ($feature === 'AUTO_INCREMENT'):
357 // never add NOT NULL if running on Oracle and we have an empty string as default
358 case ($feature === 'NOTNULL' && $GLOBALS['TYPO3_DB']->runningADOdbDriver('oci8')):
359 continue;
360 case ($feature === 'NOTNULL'):
361 $cfg .= ' NOTNULL';
362 break;
363 default:
364 $cfg .= ' ' . $featureDef['keyword'];
365 }
366
367 // Add value if found:
368 if (is_array($featureDef['value'])) {
369 if ($featureDef['value'][0] === '') {
370 $cfg .= ' "\'\'"';
371 } else {
372 $cfg .= ' ' . $featureDef['value'][1] . $this->compileAddslashes($featureDef['value'][0]) . $featureDef['value'][1];
373 if (!is_numeric($featureDef['value'][0])) {
374 $noQuote = FALSE;
375 }
376 }
377 }
378 }
379 }
380 if ($noQuote) {
381 $cfg .= ' NOQUOTE';
382 }
383 break;
384 }
385
386 // Return field definition string:
387 return $cfg;
388 }
389
390 /**
391 * Checks if the submitted feature index contains a default value definition and the default value
392 *
393 * @param array $featureIndex A feature index as produced by parseFieldDef()
394 * @return boolean
395 * @see t3lib_sqlparser::parseFieldDef()
396 */
397 public function checkEmptyDefaultValue($featureIndex) {
398 if (is_array($featureIndex['DEFAULT']['value'])) {
399 if (!is_numeric($featureIndex['DEFAULT']['value'][0]) && empty($featureIndex['DEFAULT']['value'][0])) {
400 return TRUE;
401 } else {
402 return FALSE;
403 }
404 }
405 return TRUE;
406 }
407
408 /**
409 * Implodes an array of WHERE clause configuration into a WHERE clause.
410 *
411 * DBAL-specific: The only(!) handled "calc" operators supported by parseWhereClause() are:
412 * - the bitwise logical and (&)
413 * - the addition (+)
414 * - the substraction (-)
415 * - the multiplication (*)
416 * - the division (/)
417 * - the modulo (%)
418 *
419 * @param array WHERE clause configuration
420 * @return string WHERE clause as string.
421 * @see t3lib_sqlparser::parseWhereClause()
422 */
423 public function compileWhereClause($clauseArray, $functionMapping = TRUE) {
424 switch ((string)$GLOBALS['TYPO3_DB']->handlerCfg[$GLOBALS['TYPO3_DB']->lastHandlerKey]['type']) {
425 case 'native':
426 $output = parent::compileWhereClause($clauseArray);
427 break;
428 case 'adodb':
429 // Prepare buffer variable:
430 $output = '';
431
432 // Traverse clause array:
433 if (is_array($clauseArray)) {
434 foreach($clauseArray as $k => $v) {
435
436 // Set operator:
437 $output .= $v['operator'] ? ' ' . $v['operator'] : '';
438
439 // Look for sublevel:
440 if (is_array($v['sub'])) {
441 $output .= ' (' . trim($this->compileWhereClause($v['sub'], $functionMapping)) . ')';
442 } elseif (isset($v['func']) && $v['func']['type'] === 'EXISTS') {
443 $output .= ' ' . trim($v['modifier']) . ' EXISTS (' . $this->compileSELECT($v['func']['subquery']) . ')';
444 } else {
445
446 if (isset($v['func']) && $v['func']['type'] === 'LOCATE') {
447 $output .= ' ' . trim($v['modifier']);
448 switch (TRUE) {
449 case ($GLOBALS['TYPO3_DB']->runningADOdbDriver('mssql') && $functionMapping):
450 $output .= ' CHARINDEX(';
451 $output .= $v['func']['substr'][1] . $v['func']['substr'][0] . $v['func']['substr'][1];
452 $output .= ', ' . ($v['func']['table'] ? $v['func']['table'] . '.' : '') . $v['func']['field'];
453 $output .= isset($v['func']['pos']) ? ', ' . $v['func']['pos'][0] : '';
454 $output .= ')';
455 break;
456 case ($GLOBALS['TYPO3_DB']->runningADOdbDriver('oci8') && $functionMapping):
457 $output .= ' INSTR(';
458 $output .= ($v['func']['table'] ? $v['func']['table'] . '.' : '') . $v['func']['field'];
459 $output .= ', ' . $v['func']['substr'][1] . $v['func']['substr'][0] . $v['func']['substr'][1];
460 $output .= isset($v['func']['pos']) ? ', ' . $v['func']['pos'][0] : '';
461 $output .= ')';
462 break;
463 default:
464 $output .= ' LOCATE(';
465 $output .= $v['func']['substr'][1] . $v['func']['substr'][0] . $v['func']['substr'][1];
466 $output .= ', ' . ($v['func']['table'] ? $v['func']['table'] . '.' : '') . $v['func']['field'];
467 $output .= isset($v['func']['pos']) ? ', ' . $v['func']['pos'][0] : '';
468 $output .= ')';
469 break;
470 }
471 } elseif (isset($v['func']) && $v['func']['type'] === 'IFNULL') {
472 $output .= ' ' . trim($v['modifier']) . ' ';
473 switch (TRUE) {
474 case ($GLOBALS['TYPO3_DB']->runningADOdbDriver('mssql') && $functionMapping):
475 $output .= 'ISNULL';
476 break;
477 case ($GLOBALS['TYPO3_DB']->runningADOdbDriver('oci8') && $functionMapping):
478 $output .= 'NVL';
479 break;
480 default:
481 $output .= 'IFNULL';
482 break;
483 }
484 $output .= '(';
485 $output .= ($v['func']['table'] ? $v['func']['table'] . '.' : '') . $v['func']['field'];
486 $output .= ', ' . $v['func']['default'][1] . $this->compileAddslashes($v['func']['default'][0]) . $v['func']['default'][1];
487 $output .= ')';
488 } else {
489
490 // Set field/table with modifying prefix if any:
491 $output .= ' ' . trim($v['modifier']) . ' ';
492
493 // DBAL-specific: Set calculation, if any:
494 if ($v['calc'] === '&' && $functionMapping) {
495 switch(TRUE) {
496 case $GLOBALS['TYPO3_DB']->runningADOdbDriver('oci8'):
497 // Oracle only knows BITAND(x,y) - sigh
498 $output .= 'BITAND(' . trim(($v['table'] ? $v['table'] . '.' : '') . $v['field']) . ',' . $v['calc_value'][1] . $this->compileAddslashes($v['calc_value'][0]) . $v['calc_value'][1] . ')';
499 break;
500 default:
501 // MySQL, MS SQL Server, PostgreSQL support the &-syntax
502 $output .= trim(($v['table'] ? $v['table'] . '.' : '') . $v['field']) . $v['calc'] . $v['calc_value'][1] . $this->compileAddslashes($v['calc_value'][0]) . $v['calc_value'][1];
503 break;
504 }
505 } elseif ($v['calc']) {
506 $output .= trim(($v['table'] ? $v['table'] . '.' : '') . $v['field']) . $v['calc'];
507 if (isset($v['calc_table'])) {
508 $output .= trim(($v['calc_table'] ? $v['calc_table'] . '.' : '') . $v['calc_field']);
509 } else {
510 $output .= $v['calc_value'][1] . $this->compileAddslashes($v['calc_value'][0]) . $v['calc_value'][1];
511 }
512 } elseif (!($GLOBALS['TYPO3_DB']->runningADOdbDriver('oci8') && $v['comparator'] === 'LIKE' && $functionMapping)) {
513 $output .= trim(($v['table'] ? $v['table'] . '.' : '') . $v['field']);
514 }
515 }
516
517 // Set comparator:
518 if ($v['comparator']) {
519 switch (TRUE) {
520 case ($GLOBALS['TYPO3_DB']->runningADOdbDriver('oci8') && $v['comparator'] === 'LIKE' && $functionMapping):
521 // Oracle cannot handle LIKE on CLOB fields - sigh
522 if (isset($v['value']['operator'])) {
523 $values = array();
524 foreach ($v['value']['args'] as $fieldDef) {
525 $values[] = ($fieldDef['table'] ? $fieldDef['table'] . '.' : '') . $fieldDef['field'];
526 }
527 $compareValue = ' ' . $v['value']['operator'] . '(' . implode(',', $values) . ')';
528 } else {
529 $compareValue = $v['value'][1] . $this->compileAddslashes(trim($v['value'][0], '%')) . $v['value'][1];
530 }
531 $output .= '(dbms_lob.instr(' . trim(($v['table'] ? $v['table'] . '.' : '') . $v['field']) . ', ' . $compareValue . ',1,1) > 0)';
532 break;
533 default:
534 $output .= ' ' . $v['comparator'];
535
536 // Detecting value type; list or plain:
537 if (t3lib_div::inList('NOTIN,IN', strtoupper(str_replace(array(' ', "\t", "\r", "\n"), '', $v['comparator'])))) {
538 if (isset($v['subquery'])) {
539 $output .= ' (' . $this->compileSELECT($v['subquery']) . ')';
540 } else {
541 $valueBuffer = array();
542 foreach ($v['value'] as $realValue) {
543 $valueBuffer[] = $realValue[1] . $this->compileAddslashes($realValue[0]) . $realValue[1];
544 }
545 $output .= ' (' . trim(implode(',', $valueBuffer)) . ')';
546 }
547 } else if (isset($v['value']['operator'])) {
548 $values = array();
549 foreach ($v['value']['args'] as $fieldDef) {
550 $values[] = ($fieldDef['table'] ? $fieldDef['table'] . '.' : '') . $fieldDef['field'];
551 }
552 $output .= ' ' . $v['value']['operator'] . '(' . implode(',', $values) . ')';
553 } else {
554 $output .= ' ' . $v['value'][1] . $this->compileAddslashes($v['value'][0]) . $v['value'][1];
555 }
556 break;
557 }
558 }
559 }
560 }
561 }
562 break;
563 }
564
565 return $output;
566 }
567 }
568
569
570 if (defined('TYPO3_MODE') && $TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['ext/dbal/class.ux_t3lib_sqlparser.php']) {
571 include_once($TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['ext/dbal/class.ux_t3lib_sqlparser.php']);
572 }
573
574 ?>