Resynchronized DBAL after fixing blocking bug #15535
[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: class.ux_t3lib_sqlparser.php 37143 2010-08-23 21:13:44Z xperseguers $
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 case 'ADDUNIQUE':
302 $query .= ' (' . implode(',', $components['fields']) . ')';
303 break;
304 case 'DEFAULTCHARACTERSET':
305 case 'ENGINE':
306 // ??? todo!
307 break;
308 }
309 break;
310 }
311
312 return $query;
313 }
314
315 /**
316 * Compile field definition
317 *
318 * @param array Field definition parts
319 * @return string Field definition string
320 */
321 public function compileFieldCfg($fieldCfg) {
322 switch ((string)$GLOBALS['TYPO3_DB']->handlerCfg[$GLOBALS['TYPO3_DB']->lastHandlerKey]['type']) {
323 case 'native':
324 $cfg = parent::compileFieldCfg($fieldCfg);
325 break;
326 case 'adodb':
327 // Set type:
328 $type = $GLOBALS['TYPO3_DB']->MySQLMetaType($fieldCfg['fieldType']);
329 $cfg = $type;
330
331 // Add value, if any:
332 if (strlen($fieldCfg['value']) && (in_array($type, array('C', 'C2')))) {
333 $cfg .= ' '.$fieldCfg['value'];
334 } elseif (!isset($fieldCfg['value']) && (in_array($type, array('C', 'C2')))) {
335 $cfg .= ' 255'; // add 255 as length for varchar without specified length (e.g. coming from tinytext, tinyblob)
336 }
337
338 // Add additional features:
339 $noQuote = TRUE;
340 if (is_array($fieldCfg['featureIndex'])) {
341
342 // MySQL assigns DEFAULT value automatically if NOT NULL, fake this here
343 // numeric fields get 0 as default, other fields an empty string
344 if (isset($fieldCfg['featureIndex']['NOTNULL']) && !isset($fieldCfg['featureIndex']['DEFAULT']) && !isset($fieldCfg['featureIndex']['AUTO_INCREMENT'])) {
345 switch ($type) {
346 case 'I8':
347 case 'F':
348 case 'N':
349 $fieldCfg['featureIndex']['DEFAULT'] = array('keyword' => 'DEFAULT', 'value' => array('0', ''));
350 break;
351 default:
352 $fieldCfg['featureIndex']['DEFAULT'] = array('keyword' => 'DEFAULT', 'value' => array('', '\''));
353 }
354 }
355
356 foreach ($fieldCfg['featureIndex'] as $feature => $featureDef) {
357 switch (TRUE) {
358 // unsigned only for mysql, as it is mysql specific
359 case ($feature === 'UNSIGNED' && !$GLOBALS['TYPO3_DB']->runningADOdbDriver('mysql')):
360 // auto_increment is removed, it is handled by (emulated) sequences
361 case ($feature === 'AUTO_INCREMENT'):
362 // never add NOT NULL if running on Oracle and we have an empty string as default
363 case ($feature === 'NOTNULL' && $GLOBALS['TYPO3_DB']->runningADOdbDriver('oci8')):
364 continue;
365 case ($feature === 'NOTNULL'):
366 $cfg .= ' NOTNULL';
367 break;
368 default:
369 $cfg .= ' ' . $featureDef['keyword'];
370 }
371
372 // Add value if found:
373 if (is_array($featureDef['value'])) {
374 if ($featureDef['value'][0] === '') {
375 $cfg .= ' "\'\'"';
376 } else {
377 $cfg .= ' ' . $featureDef['value'][1] . $this->compileAddslashes($featureDef['value'][0]) . $featureDef['value'][1];
378 if (!is_numeric($featureDef['value'][0])) {
379 $noQuote = FALSE;
380 }
381 }
382 }
383 }
384 }
385 if ($noQuote) {
386 $cfg .= ' NOQUOTE';
387 }
388 break;
389 }
390
391 // Return field definition string:
392 return $cfg;
393 }
394
395 /**
396 * Checks if the submitted feature index contains a default value definition and the default value
397 *
398 * @param array $featureIndex A feature index as produced by parseFieldDef()
399 * @return boolean
400 * @see t3lib_sqlparser::parseFieldDef()
401 */
402 public function checkEmptyDefaultValue($featureIndex) {
403 if (is_array($featureIndex['DEFAULT']['value'])) {
404 if (!is_numeric($featureIndex['DEFAULT']['value'][0]) && empty($featureIndex['DEFAULT']['value'][0])) {
405 return TRUE;
406 } else {
407 return FALSE;
408 }
409 }
410 return TRUE;
411 }
412
413 /**
414 * Implodes an array of WHERE clause configuration into a WHERE clause.
415 *
416 * DBAL-specific: The only(!) handled "calc" operators supported by parseWhereClause() are:
417 * - the bitwise logical and (&)
418 * - the addition (+)
419 * - the substraction (-)
420 * - the multiplication (*)
421 * - the division (/)
422 * - the modulo (%)
423 *
424 * @param array WHERE clause configuration
425 * @return string WHERE clause as string.
426 * @see t3lib_sqlparser::parseWhereClause()
427 */
428 public function compileWhereClause($clauseArray, $functionMapping = TRUE) {
429 switch ((string)$GLOBALS['TYPO3_DB']->handlerCfg[$GLOBALS['TYPO3_DB']->lastHandlerKey]['type']) {
430 case 'native':
431 $output = parent::compileWhereClause($clauseArray);
432 break;
433 case 'adodb':
434 // Prepare buffer variable:
435 $output = '';
436
437 // Traverse clause array:
438 if (is_array($clauseArray)) {
439 foreach($clauseArray as $k => $v) {
440
441 // Set operator:
442 $output .= $v['operator'] ? ' ' . $v['operator'] : '';
443
444 // Look for sublevel:
445 if (is_array($v['sub'])) {
446 $output .= ' (' . trim($this->compileWhereClause($v['sub'], $functionMapping)) . ')';
447 } elseif (isset($v['func']) && $v['func']['type'] === 'EXISTS') {
448 $output .= ' ' . trim($v['modifier']) . ' EXISTS (' . $this->compileSELECT($v['func']['subquery']) . ')';
449 } else {
450
451 if (isset($v['func']) && $v['func']['type'] === 'LOCATE') {
452 $output .= ' ' . trim($v['modifier']);
453 switch (TRUE) {
454 case ($GLOBALS['TYPO3_DB']->runningADOdbDriver('mssql') && $functionMapping):
455 $output .= ' CHARINDEX(';
456 $output .= $v['func']['substr'][1] . $v['func']['substr'][0] . $v['func']['substr'][1];
457 $output .= ', ' . ($v['func']['table'] ? $v['func']['table'] . '.' : '') . $v['func']['field'];
458 $output .= isset($v['func']['pos']) ? ', ' . $v['func']['pos'][0] : '';
459 $output .= ')';
460 break;
461 case ($GLOBALS['TYPO3_DB']->runningADOdbDriver('oci8') && $functionMapping):
462 $output .= ' INSTR(';
463 $output .= ($v['func']['table'] ? $v['func']['table'] . '.' : '') . $v['func']['field'];
464 $output .= ', ' . $v['func']['substr'][1] . $v['func']['substr'][0] . $v['func']['substr'][1];
465 $output .= isset($v['func']['pos']) ? ', ' . $v['func']['pos'][0] : '';
466 $output .= ')';
467 break;
468 default:
469 $output .= ' LOCATE(';
470 $output .= $v['func']['substr'][1] . $v['func']['substr'][0] . $v['func']['substr'][1];
471 $output .= ', ' . ($v['func']['table'] ? $v['func']['table'] . '.' : '') . $v['func']['field'];
472 $output .= isset($v['func']['pos']) ? ', ' . $v['func']['pos'][0] : '';
473 $output .= ')';
474 break;
475 }
476 } elseif (isset($v['func']) && $v['func']['type'] === 'IFNULL') {
477 $output .= ' ' . trim($v['modifier']) . ' ';
478 switch (TRUE) {
479 case ($GLOBALS['TYPO3_DB']->runningADOdbDriver('mssql') && $functionMapping):
480 $output .= 'ISNULL';
481 break;
482 case ($GLOBALS['TYPO3_DB']->runningADOdbDriver('oci8') && $functionMapping):
483 $output .= 'NVL';
484 break;
485 default:
486 $output .= 'IFNULL';
487 break;
488 }
489 $output .= '(';
490 $output .= ($v['func']['table'] ? $v['func']['table'] . '.' : '') . $v['func']['field'];
491 $output .= ', ' . $v['func']['default'][1] . $this->compileAddslashes($v['func']['default'][0]) . $v['func']['default'][1];
492 $output .= ')';
493 } elseif (isset($v['func']) && $v['func']['type'] === 'FIND_IN_SET') {
494 $output .= ' ' . trim($v['modifier']) . ' ';
495 if ($functionMapping) {
496 switch (TRUE) {
497 case ($GLOBALS['TYPO3_DB']->runningADOdbDriver('mssql')):
498 $field = ($v['func']['table'] ? $v['func']['table'] . '.' : '') . $v['func']['field'];
499 if (!isset($v['func']['str_like'])) {
500 $v['func']['str_like'] = $v['func']['str'][0];
501 }
502 $output .= '\',\'+' . $field . '+\',\' LIKE \'%,' . $v['func']['str_like'] . ',%\'';
503 break;
504 case ($GLOBALS['TYPO3_DB']->runningADOdbDriver('oci8')):
505 $field = ($v['func']['table'] ? $v['func']['table'] . '.' : '') . $v['func']['field'];
506 if (!isset($v['func']['str_like'])) {
507 $v['func']['str_like'] = $v['func']['str'][0];
508 }
509 $output .= '\',\'||' . $field . '||\',\' LIKE \'%,' . $v['func']['str_like'] . ',%\'';
510 break;
511 case ($GLOBALS['TYPO3_DB']->runningADOdbDriver('postgres')):
512 $output .= ' FIND_IN_SET(';
513 $output .= $v['func']['str'][1] . $v['func']['str'][0] . $v['func']['str'][1];
514 $output .= ', ' . ($v['func']['table'] ? $v['func']['table'] . '.' : '') . $v['func']['field'];
515 $output .= ') != 0';
516 break;
517 default:
518 $field = ($v['func']['table'] ? $v['func']['table'] . '.' : '') . $v['func']['field'];
519 if (!isset($v['func']['str_like'])) {
520 $v['func']['str_like'] = $v['func']['str'][0];
521 }
522 $output .= '('
523 . $field . ' LIKE \'%,' . $v['func']['str_like'] . ',%\''
524 . ' OR ' . $field . ' LIKE \'' . $v['func']['str_like'] . ',%\''
525 . ' OR ' . $field . ' LIKE \'%,' . $v['func']['str_like'] . '\''
526 . ' OR ' . $field . '= ' . $v['func']['str'][1] . $v['func']['str'][0] . $v['func']['str'][1]
527 . ')';
528 break;
529 }
530 } else /* !$functionMapping */ {
531 switch (TRUE) {
532 case ($GLOBALS['TYPO3_DB']->runningADOdbDriver('mssql')):
533 case ($GLOBALS['TYPO3_DB']->runningADOdbDriver('oci8')):
534 case ($GLOBALS['TYPO3_DB']->runningADOdbDriver('postgres')):
535 $output .= ' FIND_IN_SET(';
536 $output .= $v['func']['str'][1] . $v['func']['str'][0] . $v['func']['str'][1];
537 $output .= ', ' . ($v['func']['table'] ? $v['func']['table'] . '.' : '') . $v['func']['field'];
538 $output .= ')';
539 break;
540 default:
541 $field = ($v['func']['table'] ? $v['func']['table'] . '.' : '') . $v['func']['field'];
542 if (!isset($v['func']['str_like'])) {
543 $v['func']['str_like'] = $v['func']['str'][0];
544 }
545 $output .= '('
546 . $field . ' LIKE \'%,' . $v['func']['str_like'] . ',%\''
547 . ' OR ' . $field . ' LIKE \'' . $v['func']['str_like'] . ',%\''
548 . ' OR ' . $field . ' LIKE \'%,' . $v['func']['str_like'] . '\''
549 . ' OR ' . $field . '= ' . $v['func']['str'][1] . $v['func']['str'][0] . $v['func']['str'][1]
550 . ')';
551 break;
552 }
553 }
554 } else {
555
556 // Set field/table with modifying prefix if any:
557 $output .= ' ' . trim($v['modifier']) . ' ';
558
559 // DBAL-specific: Set calculation, if any:
560 if ($v['calc'] === '&' && $functionMapping) {
561 switch(TRUE) {
562 case $GLOBALS['TYPO3_DB']->runningADOdbDriver('oci8'):
563 // Oracle only knows BITAND(x,y) - sigh
564 $output .= 'BITAND(' . trim(($v['table'] ? $v['table'] . '.' : '') . $v['field']) . ',' . $v['calc_value'][1] . $this->compileAddslashes($v['calc_value'][0]) . $v['calc_value'][1] . ')';
565 break;
566 default:
567 // MySQL, MS SQL Server, PostgreSQL support the &-syntax
568 $output .= trim(($v['table'] ? $v['table'] . '.' : '') . $v['field']) . $v['calc'] . $v['calc_value'][1] . $this->compileAddslashes($v['calc_value'][0]) . $v['calc_value'][1];
569 break;
570 }
571 } elseif ($v['calc']) {
572 $output .= trim(($v['table'] ? $v['table'] . '.' : '') . $v['field']) . $v['calc'];
573 if (isset($v['calc_table'])) {
574 $output .= trim(($v['calc_table'] ? $v['calc_table'] . '.' : '') . $v['calc_field']);
575 } else {
576 $output .= $v['calc_value'][1] . $this->compileAddslashes($v['calc_value'][0]) . $v['calc_value'][1];
577 }
578 } elseif (!($GLOBALS['TYPO3_DB']->runningADOdbDriver('oci8') && preg_match('/(NOT )?LIKE( BINARY)?/', $v['comparator']) && $functionMapping)) {
579 $output .= trim(($v['table'] ? $v['table'] . '.' : '') . $v['field']);
580 }
581 }
582
583 // Set comparator:
584 if ($v['comparator']) {
585 $isLikeOperator = preg_match('/(NOT )?LIKE( BINARY)?/', $v['comparator']);
586 switch (TRUE) {
587 case ($GLOBALS['TYPO3_DB']->runningADOdbDriver('oci8') && $isLikeOperator && $functionMapping):
588 // Oracle cannot handle LIKE on CLOB fields - sigh
589 if (isset($v['value']['operator'])) {
590 $values = array();
591 foreach ($v['value']['args'] as $fieldDef) {
592 $values[] = ($fieldDef['table'] ? $fieldDef['table'] . '.' : '') . $fieldDef['field'];
593 }
594 $compareValue = ' ' . $v['value']['operator'] . '(' . implode(',', $values) . ')';
595 } else {
596 $compareValue = $v['value'][1] . $this->compileAddslashes(trim($v['value'][0], '%')) . $v['value'][1];
597 }
598 if (t3lib_div::isFirstPartOfStr($v['comparator'], 'NOT')) {
599 $output .= 'NOT ';
600 }
601 // To be on the safe side
602 $isLob = TRUE;
603 if ($v['table']) {
604 // Table and field names are quoted:
605 $tableName = substr($v['table'], 1, strlen($v['table']) - 2);
606 $fieldName = substr($v['field'], 1, strlen($v['field']) - 2);
607 $fieldType = $GLOBALS['TYPO3_DB']->sql_field_metatype($tableName, $fieldName);
608 $isLob = ($fieldType === 'B' || $fieldType === 'XL');
609 }
610 if ($isLob) {
611 $output .= '(dbms_lob.instr(' . trim(($v['table'] ? $v['table'] . '.' : '') . $v['field']) . ', ' . $compareValue . ',1,1) > 0)';
612 } else {
613 $output .= '(instr(' . trim(($v['table'] ? $v['table'] . '.' : '') . $v['field']) . ', ' . $compareValue . ',1,1) > 0)';
614 }
615 break;
616 default:
617 if ($isLikeOperator && $functionMapping) {
618 if ($GLOBALS['TYPO3_DB']->runningADOdbDriver('postgres') ||
619 $GLOBALS['TYPO3_DB']->runningADOdbDriver('postgres64') ||
620 $GLOBALS['TYPO3_DB']->runningADOdbDriver('postgres7') ||
621 $GLOBALS['TYPO3_DB']->runningADOdbDriver('postgres8')) {
622
623 // Remap (NOT)? LIKE to (NOT)? ILIKE
624 // and (NOT)? LIKE BINARY to (NOT)? LIKE
625 switch ($v['comparator']) {
626 // Remap (NOT)? LIKE to (NOT)? ILIKE
627 case 'LIKE':
628 $v['comparator'] = 'ILIKE';
629 break;
630 case 'NOT LIKE':
631 $v['comparator'] = 'NOT ILIKE';
632 break;
633 default:
634 $v['comparator'] = str_replace(' BINARY', '', $v['comparator']);
635 break;
636 }
637 } else {
638 // No more BINARY operator
639 $v['comparator'] = str_replace(' BINARY', '', $v['comparator']);
640 }
641 }
642
643 $output .= ' ' . $v['comparator'];
644
645 // Detecting value type; list or plain:
646 if (t3lib_div::inList('NOTIN,IN', strtoupper(str_replace(array(' ', TAB, CR, LF), '', $v['comparator'])))) {
647 if (isset($v['subquery'])) {
648 $output .= ' (' . $this->compileSELECT($v['subquery']) . ')';
649 } else {
650 $valueBuffer = array();
651 foreach ($v['value'] as $realValue) {
652 $valueBuffer[] = $realValue[1] . $this->compileAddslashes($realValue[0]) . $realValue[1];
653 }
654 $output .= ' (' . trim(implode(',', $valueBuffer)) . ')';
655 }
656 } else if (t3lib_div::inList('BETWEEN,NOT BETWEEN', $v['comparator'])) {
657 $lbound = $v['values'][0];
658 $ubound = $v['values'][1];
659 $output .= ' ' . $lbound[1] . $this->compileAddslashes($lbound[0]) . $lbound[1];
660 $output .= ' AND ';
661 $output .= $ubound[1] . $this->compileAddslashes($ubound[0]) . $ubound[1];
662 } else if (isset($v['value']['operator'])) {
663 $values = array();
664 foreach ($v['value']['args'] as $fieldDef) {
665 $values[] = ($fieldDef['table'] ? $fieldDef['table'] . '.' : '') . $fieldDef['field'];
666 }
667 $output .= ' ' . $v['value']['operator'] . '(' . implode(',', $values) . ')';
668 } else {
669 $output .= ' ' . $v['value'][1] . $this->compileAddslashes($v['value'][0]) . $v['value'][1];
670 }
671 break;
672 }
673 }
674 }
675 }
676 }
677 break;
678 }
679
680 return $output;
681 }
682 }
683
684
685 if (defined('TYPO3_MODE') && $TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['ext/dbal/class.ux_t3lib_sqlparser.php']) {
686 include_once($TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['ext/dbal/class.ux_t3lib_sqlparser.php']);
687 }
688
689 ?>