TYPO3 API  SVNRelease
class.ux_t3lib_sqlparser.php
Go to the documentation of this file.
00001 <?php
00002 /***************************************************************
00003  *  Copyright notice
00004  *
00005  *  (c) 2004-2009 Kasper Skårhøj (kasperYYYY@typo3.com)
00006  *  (c) 2004-2009 Karsten Dambekalns <karsten@typo3.org>
00007  *  (c) 2009-2010 Xavier Perseguers <typo3@perseguers.ch>
00008  *  All rights reserved
00009  *
00010  *  This script is part of the TYPO3 project. The TYPO3 project is
00011  *  free software; you can redistribute it and/or modify
00012  *  it under the terms of the GNU General Public License as published by
00013  *  the Free Software Foundation; either version 2 of the License, or
00014  *  (at your option) any later version.
00015  *
00016  *  The GNU General Public License can be found at
00017  *  http://www.gnu.org/copyleft/gpl.html.
00018  *  A copy is found in the textfile GPL.txt and important notices to the license
00019  *  from the author is found in LICENSE.txt distributed with these scripts.
00020  *
00021  *
00022  *  This script is distributed in the hope that it will be useful,
00023  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00024  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00025  *  GNU General Public License for more details.
00026  *
00027  *  This copyright notice MUST APPEAR in all copies of the script!
00028  ***************************************************************/
00029 /**
00030  * PHP SQL engine
00031  *
00032  * $Id: class.ux_t3lib_sqlparser.php 42538 2011-01-24 15:04:19Z xperseguers $
00033  *
00034  * @author  Kasper Skårhøj <kasperYYYY@typo3.com>
00035  * @author  Karsten Dambekalns <k.dambekalns@fishfarm.de>
00036  * @author  Xavier Perseguers <typo3@perseguers.ch>
00037  */
00038 
00039 
00040 /**
00041  * PHP SQL engine / server
00042  *
00043  * @author  Kasper Skårhøj <kasper@typo3.com>
00044  * @package TYPO3
00045  * @subpackage t3lib
00046  */
00047 class ux_t3lib_sqlparser extends t3lib_sqlparser {
00048 
00049     /**
00050      * Compiles a "SELECT [output] FROM..:" field list based on input array (made with ->parseFieldList())
00051      * Can also compile field lists for ORDER BY and GROUP BY.
00052      *
00053      * @param   array       Array of select fields, (made with ->parseFieldList())
00054      * @param   boolean     Whether comments should be compiled
00055      * @param   boolean     Whether function mapping should take place
00056      * @return  string      Select field string
00057      * @see parseFieldList()
00058      */
00059     public function compileFieldList($selectFields, $compileComments = TRUE, $functionMapping = TRUE) {
00060         switch ((string) $GLOBALS['TYPO3_DB']->handlerCfg[$GLOBALS['TYPO3_DB']->lastHandlerKey]['type']) {
00061             case 'native':
00062                 $output = parent::compileFieldList($selectFields, $compileComments);
00063                 break;
00064             case 'adodb':
00065                 $output = '';
00066                 // Traverse the selectFields if any:
00067                 if (is_array($selectFields)) {
00068                     $outputParts = array();
00069                     foreach ($selectFields as $k => $v) {
00070 
00071                         // Detecting type:
00072                         switch ($v['type']) {
00073                             case 'function':
00074                                 $outputParts[$k] = $v['function'] . '(' . $v['func_content'] . ')';
00075                                 break;
00076                             case 'flow-control':
00077                                 if ($v['flow-control']['type'] === 'CASE') {
00078                                     $outputParts[$k] = $this->compileCaseStatement($v['flow-control'], $functionMapping);
00079                                 }
00080                                 break;
00081                             case 'field':
00082                                 $outputParts[$k] = ($v['distinct'] ? $v['distinct'] : '') . ($v['table'] ? $v['table'] . '.' : '') . $v['field'];
00083                                 break;
00084                         }
00085 
00086                         // Alias:
00087                         if ($v['as']) {
00088                             $outputParts[$k] .= ' ' . $v['as_keyword'] . ' ' . $v['as'];
00089                         }
00090 
00091                         // Specifically for ORDER BY and GROUP BY field lists:
00092                         if ($v['sortDir']) {
00093                             $outputParts[$k] .= ' ' . $v['sortDir'];
00094                         }
00095                     }
00096                     // TODO: Handle SQL hints in comments according to current DBMS
00097                     if ( /* $compileComments */
00098                             FALSE && $selectFields[0]['comments']) {
00099                         $output = $selectFields[0]['comments'] . ' ';
00100                     }
00101                     $output .= implode(', ', $outputParts);
00102                 }
00103                 break;
00104         }
00105         return $output;
00106     }
00107 
00108     /**
00109      * Compiles a CASE ... WHEN flow-control construct based on input array (made with ->parseCaseStatement())
00110      *
00111      * @param   array       Array of case components, (made with ->parseCaseStatement())
00112      * @param   boolean     Whether function mapping should take place
00113      * @return  string      case when string
00114      * @see parseCaseStatement()
00115      */
00116     protected function compileCaseStatement(array $components, $functionMapping = TRUE) {
00117         switch ((string) $GLOBALS['TYPO3_DB']->handlerCfg[$GLOBALS['TYPO3_DB']->lastHandlerKey]['type']) {
00118             case 'native':
00119                 $output = parent::compileCaseStatement($components);
00120                 break;
00121             case 'adodb':
00122                 $statement = 'CASE';
00123                 if (isset($components['case_field'])) {
00124                     $statement .= ' ' . $components['case_field'];
00125                 } elseif (isset($components['case_value'])) {
00126                     $statement .= ' ' . $components['case_value'][1] . $components['case_value'][0] . $components['case_value'][1];
00127                 }
00128                 foreach ($components['when'] as $when) {
00129                     $statement .= ' WHEN ';
00130                     $statement .= $this->compileWhereClause($when['when_value'], $functionMapping);
00131                     $statement .= ' THEN ';
00132                     $statement .= $when['then_value'][1] . $when['then_value'][0] . $when['then_value'][1];
00133                 }
00134                 if (isset($components['else'])) {
00135                     $statement .= ' ELSE ';
00136                     $statement .= $components['else'][1] . $components['else'][0] . $components['else'][1];
00137                 }
00138                 $statement .= ' END';
00139                 $output = $statement;
00140                 break;
00141         }
00142         return $output;
00143     }
00144 
00145     /**
00146      * Add slashes function used for compiling queries
00147      * This method overrides the method from t3lib_sqlparser because
00148      * the input string is already properly escaped.
00149      *
00150      * @param   string      Input string
00151      * @return  string      Output string
00152      */
00153     protected function compileAddslashes($str) {
00154         return $str;
00155     }
00156 
00157     /*************************
00158      *
00159      * Compiling queries
00160      *
00161      *************************/
00162 
00163     /**
00164      * Compiles an INSERT statement from components array
00165      *
00166      * @param array Array of SQL query components
00167      * @return string SQL INSERT query / array
00168      * @see parseINSERT()
00169      */
00170     protected function compileINSERT($components) {
00171         switch ((string) $GLOBALS['TYPO3_DB']->handlerCfg[$GLOBALS['TYPO3_DB']->lastHandlerKey]['type']) {
00172             case 'native':
00173                 $query = parent::compileINSERT($components);
00174                 break;
00175             case 'adodb':
00176                 $values = array();
00177 
00178                 if (isset($components['VALUES_ONLY']) && is_array($components['VALUES_ONLY'])) {
00179                     $valuesComponents = $components['EXTENDED'] === '1' ? $components['VALUES_ONLY'] : array($components['VALUES_ONLY']);
00180                     $tableFields = array_keys($GLOBALS['TYPO3_DB']->cache_fieldType[$components['TABLE']]);
00181                 } else {
00182                     $valuesComponents = $components['EXTENDED'] === '1' ? $components['FIELDS'] : array($components['FIELDS']);
00183                     $tableFields = array_keys($valuesComponents[0]);
00184                 }
00185 
00186                 foreach ($valuesComponents as $valuesComponent) {
00187                     $fields = array();
00188                     $fc = 0;
00189                     foreach ($valuesComponent as $fV) {
00190                         $fields[$tableFields[$fc++]] = $fV[0];
00191                     }
00192                     $values[] = $fields;
00193                 }
00194                 $query = count($values) === 1 ? $values[0] : $values;
00195                 break;
00196         }
00197 
00198         return $query;
00199     }
00200 
00201     /**
00202      * Compiles a DROP TABLE statement from components array
00203      *
00204      * @param array Array of SQL query components
00205      * @return string SQL DROP TABLE query
00206      * @see compileSQL()
00207      */
00208     private function compileDROPTABLE($components) {
00209         switch ((string) $GLOBALS['TYPO3_DB']->handlerCfg[$GLOBALS['TYPO3_DB']->lastHandlerKey]['type']) {
00210             case 'native':
00211                 $query = 'DROP TABLE' . ($components['ifExists'] ? ' IF EXISTS' : '') . ' ' . $components['TABLE'];
00212                 break;
00213             case 'adodb':
00214                 $handlerKey = $GLOBALS['TYPO3_DB']->handler_getFromTableList($components['TABLE']);
00215                 $tableName = $GLOBALS['TYPO3_DB']->quoteName($components['TABLE'], $handlerKey, TRUE);
00216                 $query = $GLOBALS['TYPO3_DB']->handlerInstance[$handlerKey]->DataDictionary->DropTableSQL($tableName);
00217                 break;
00218         }
00219 
00220         return $query;
00221     }
00222 
00223     /**
00224      * Compiles a CREATE TABLE statement from components array
00225      *
00226      * @param   array       Array of SQL query components
00227      * @return  array       array with SQL CREATE TABLE/INDEX command(s)
00228      * @see parseCREATETABLE()
00229      */
00230     public function compileCREATETABLE($components) {
00231         // Execute query (based on handler derived from the TABLE name which we actually know for once!)
00232         switch ((string) $GLOBALS['TYPO3_DB']->handlerCfg[$GLOBALS['TYPO3_DB']->handler_getFromTableList($components['TABLE'])]['type']) {
00233             case 'native':
00234                 $query[] = parent::compileCREATETABLE($components);
00235                 break;
00236             case 'adodb':
00237                 // Create fields and keys:
00238                 $fieldsKeys = array();
00239                 $indexKeys = array();
00240 
00241                 foreach ($components['FIELDS'] as $fN => $fCfg) {
00242                     $handlerKey = $GLOBALS['TYPO3_DB']->handler_getFromTableList($components['TABLE']);
00243                     $fieldsKeys[$fN] = $GLOBALS['TYPO3_DB']->quoteName($fN, $handlerKey, TRUE) . ' ' . $this->compileFieldCfg($fCfg['definition']);
00244                 }
00245 
00246                 if (isset($components['KEYS']) && is_array($components['KEYS'])) {
00247                     foreach ($components['KEYS'] as $kN => $kCfg) {
00248                         if ($kN === 'PRIMARYKEY') {
00249                             foreach ($kCfg as $n => $field) {
00250                                 $fieldsKeys[$field] .= ' PRIMARY';
00251                             }
00252                         } elseif ($kN === 'UNIQUE') {
00253                             foreach ($kCfg as $n => $field) {
00254                                 $indexKeys = array_merge($indexKeys, $GLOBALS['TYPO3_DB']->handlerInstance[$GLOBALS['TYPO3_DB']->handler_getFromTableList($components['TABLE'])]->DataDictionary->CreateIndexSQL($n, $components['TABLE'], $field, array('UNIQUE')));
00255                             }
00256                         } else {
00257                             $indexKeys = array_merge($indexKeys, $GLOBALS['TYPO3_DB']->handlerInstance[$GLOBALS['TYPO3_DB']->handler_getFromTableList($components['TABLE'])]->DataDictionary->CreateIndexSQL($components['TABLE'] . '_' . $kN, $components['TABLE'], $kCfg));
00258                         }
00259                     }
00260                 }
00261 
00262                 // Generally create without OID on PostgreSQL
00263                 $tableOptions = array('postgres' => 'WITHOUT OIDS');
00264 
00265                 // Fetch table/index generation query:
00266                 $tableName = $GLOBALS['TYPO3_DB']->quoteName($components['TABLE'], NULL, TRUE);
00267                 $query = array_merge($GLOBALS['TYPO3_DB']->handlerInstance[$GLOBALS['TYPO3_DB']->lastHandlerKey]->DataDictionary->CreateTableSQL($tableName, implode(',' . chr(10), $fieldsKeys), $tableOptions), $indexKeys);
00268                 break;
00269         }
00270 
00271         return $query;
00272     }
00273 
00274     /**
00275      * Compiles an ALTER TABLE statement from components array
00276      *
00277      * @param array Array of SQL query components
00278      * @return string SQL ALTER TABLE query
00279      * @see parseALTERTABLE()
00280      */
00281     public function compileALTERTABLE($components) {
00282         // Execute query (based on handler derived from the TABLE name which we actually know for once!)
00283         switch ((string) $GLOBALS['TYPO3_DB']->handlerCfg[$GLOBALS['TYPO3_DB']->lastHandlerKey]['type']) {
00284             case 'native':
00285                 $query[] = parent::compileALTERTABLE($components);
00286                 break;
00287             case 'adodb':
00288                 $tableName = $GLOBALS['TYPO3_DB']->quoteName($components['TABLE'], NULL, TRUE);
00289                 $fieldName = $GLOBALS['TYPO3_DB']->quoteName($components['FIELD'], NULL, TRUE);
00290                 switch (strtoupper(str_replace(array(' ', "\n", "\r", "\t"), '', $components['action']))) {
00291                     case 'ADD':
00292                         $query = $GLOBALS['TYPO3_DB']->handlerInstance[$GLOBALS['TYPO3_DB']->lastHandlerKey]->DataDictionary->AddColumnSQL($tableName, $fieldName . ' ' . $this->compileFieldCfg($components['definition']));
00293                         break;
00294                     case 'CHANGE':
00295                         $query = $GLOBALS['TYPO3_DB']->handlerInstance[$GLOBALS['TYPO3_DB']->lastHandlerKey]->DataDictionary->AlterColumnSQL($tableName, $fieldName . ' ' . $this->compileFieldCfg($components['definition']));
00296                         break;
00297                     case 'DROP':
00298                     case 'DROPKEY':
00299                         break;
00300                     case 'ADDKEY':
00301                     case 'ADDPRIMARYKEY':
00302                     case 'ADDUNIQUE':
00303                         $query .= ' (' . implode(',', $components['fields']) . ')';
00304                         break;
00305                     case 'DEFAULTCHARACTERSET':
00306                     case 'ENGINE':
00307                         // ??? todo!
00308                         break;
00309                 }
00310                 break;
00311         }
00312 
00313         return $query;
00314     }
00315 
00316     /**
00317      * Compile field definition
00318      *
00319      * @param   array       Field definition parts
00320      * @return  string      Field definition string
00321      */
00322     public function compileFieldCfg($fieldCfg) {
00323         switch ((string) $GLOBALS['TYPO3_DB']->handlerCfg[$GLOBALS['TYPO3_DB']->lastHandlerKey]['type']) {
00324             case 'native':
00325                 $cfg = parent::compileFieldCfg($fieldCfg);
00326                 break;
00327             case 'adodb':
00328                 // Set type:
00329                 $type = $GLOBALS['TYPO3_DB']->MySQLMetaType($fieldCfg['fieldType']);
00330                 $cfg = $type;
00331 
00332                 // Add value, if any:
00333                 if (strlen($fieldCfg['value']) && (in_array($type, array('C', 'C2')))) {
00334                     $cfg .= ' ' . $fieldCfg['value'];
00335                 } elseif (!isset($fieldCfg['value']) && (in_array($type, array('C', 'C2')))) {
00336                     $cfg .= ' 255'; // add 255 as length for varchar without specified length (e.g. coming from tinytext, tinyblob)
00337                 }
00338 
00339                 // Add additional features:
00340                 $noQuote = TRUE;
00341                 if (is_array($fieldCfg['featureIndex'])) {
00342 
00343                     // MySQL assigns DEFAULT value automatically if NOT NULL, fake this here
00344                     // numeric fields get 0 as default, other fields an empty string
00345                     if (isset($fieldCfg['featureIndex']['NOTNULL']) && !isset($fieldCfg['featureIndex']['DEFAULT']) && !isset($fieldCfg['featureIndex']['AUTO_INCREMENT'])) {
00346                         switch ($type) {
00347                             case 'I8':
00348                             case 'F':
00349                             case 'N':
00350                                 $fieldCfg['featureIndex']['DEFAULT'] = array('keyword' => 'DEFAULT', 'value' => array('0', ''));
00351                                 break;
00352                             default:
00353                                 $fieldCfg['featureIndex']['DEFAULT'] = array('keyword' => 'DEFAULT', 'value' => array('', '\''));
00354                         }
00355                     }
00356 
00357                     foreach ($fieldCfg['featureIndex'] as $feature => $featureDef) {
00358                         switch (TRUE) {
00359                             // unsigned only for mysql, as it is mysql specific
00360                             case ($feature === 'UNSIGNED' && !$GLOBALS['TYPO3_DB']->runningADOdbDriver('mysql')):
00361                                 // auto_increment is removed, it is handled by (emulated) sequences
00362                             case ($feature === 'AUTO_INCREMENT'):
00363                                 // never add NOT NULL if running on Oracle and we have an empty string as default
00364                             case ($feature === 'NOTNULL' && $GLOBALS['TYPO3_DB']->runningADOdbDriver('oci8')):
00365                                 continue;
00366                             case ($feature === 'NOTNULL'):
00367                                 $cfg .= ' NOTNULL';
00368                                 break;
00369                             default:
00370                                 $cfg .= ' ' . $featureDef['keyword'];
00371                         }
00372 
00373                         // Add value if found:
00374                         if (is_array($featureDef['value'])) {
00375                             if ($featureDef['value'][0] === '') {
00376                                 $cfg .= ' "\'\'"';
00377                             } else {
00378                                 $cfg .= ' ' . $featureDef['value'][1] . $this->compileAddslashes($featureDef['value'][0]) . $featureDef['value'][1];
00379                                 if (!is_numeric($featureDef['value'][0])) {
00380                                     $noQuote = FALSE;
00381                                 }
00382                             }
00383                         }
00384                     }
00385                 }
00386                 if ($noQuote) {
00387                     $cfg .= ' NOQUOTE';
00388                 }
00389                 break;
00390         }
00391 
00392         // Return field definition string:
00393         return $cfg;
00394     }
00395 
00396     /**
00397      * Checks if the submitted feature index contains a default value definition and the default value
00398      *
00399      * @param array $featureIndex A feature index as produced by parseFieldDef()
00400      * @return boolean
00401      * @see t3lib_sqlparser::parseFieldDef()
00402      */
00403     public function checkEmptyDefaultValue($featureIndex) {
00404         if (is_array($featureIndex['DEFAULT']['value'])) {
00405             if (!is_numeric($featureIndex['DEFAULT']['value'][0]) && empty($featureIndex['DEFAULT']['value'][0])) {
00406                 return TRUE;
00407             } else {
00408                 return FALSE;
00409             }
00410         }
00411         return TRUE;
00412     }
00413 
00414     /**
00415      * Implodes an array of WHERE clause configuration into a WHERE clause.
00416      *
00417      * DBAL-specific: The only(!) handled "calc" operators supported by parseWhereClause() are:
00418      * - the bitwise logical and (&)
00419      * - the addition (+)
00420      * - the substraction (-)
00421      * - the multiplication (*)
00422      * - the division (/)
00423      * - the modulo (%)
00424      *
00425      * @param array WHERE clause configuration
00426      * @return string WHERE clause as string.
00427      * @see t3lib_sqlparser::parseWhereClause()
00428      */
00429     public function compileWhereClause($clauseArray, $functionMapping = TRUE) {
00430         switch ((string) $GLOBALS['TYPO3_DB']->handlerCfg[$GLOBALS['TYPO3_DB']->lastHandlerKey]['type']) {
00431             case 'native':
00432                 $output = parent::compileWhereClause($clauseArray);
00433                 break;
00434             case 'adodb':
00435                 // Prepare buffer variable:
00436                 $output = '';
00437 
00438                 // Traverse clause array:
00439                 if (is_array($clauseArray)) {
00440                     foreach ($clauseArray as $k => $v) {
00441 
00442                         // Set operator:
00443                         $output .= $v['operator'] ? ' ' . $v['operator'] : '';
00444 
00445                         // Look for sublevel:
00446                         if (is_array($v['sub'])) {
00447                             $output .= ' (' . trim($this->compileWhereClause($v['sub'], $functionMapping)) . ')';
00448                         } elseif (isset($v['func']) && $v['func']['type'] === 'EXISTS') {
00449                             $output .= ' ' . trim($v['modifier']) . ' EXISTS (' . $this->compileSELECT($v['func']['subquery']) . ')';
00450                         } else {
00451 
00452                             if (isset($v['func']) && $v['func']['type'] === 'LOCATE') {
00453                                 $output .= ' ' . trim($v['modifier']);
00454                                 switch (TRUE) {
00455                                     case ($GLOBALS['TYPO3_DB']->runningADOdbDriver('mssql') && $functionMapping):
00456                                         $output .= ' CHARINDEX(';
00457                                         $output .= $v['func']['substr'][1] . $v['func']['substr'][0] . $v['func']['substr'][1];
00458                                         $output .= ', ' . ($v['func']['table'] ? $v['func']['table'] . '.' : '') . $v['func']['field'];
00459                                         $output .= isset($v['func']['pos']) ? ', ' . $v['func']['pos'][0] : '';
00460                                         $output .= ')';
00461                                         break;
00462                                     case ($GLOBALS['TYPO3_DB']->runningADOdbDriver('oci8') && $functionMapping):
00463                                         $output .= ' INSTR(';
00464                                         $output .= ($v['func']['table'] ? $v['func']['table'] . '.' : '') . $v['func']['field'];
00465                                         $output .= ', ' . $v['func']['substr'][1] . $v['func']['substr'][0] . $v['func']['substr'][1];
00466                                         $output .= isset($v['func']['pos']) ? ', ' . $v['func']['pos'][0] : '';
00467                                         $output .= ')';
00468                                         break;
00469                                     default:
00470                                         $output .= ' LOCATE(';
00471                                         $output .= $v['func']['substr'][1] . $v['func']['substr'][0] . $v['func']['substr'][1];
00472                                         $output .= ', ' . ($v['func']['table'] ? $v['func']['table'] . '.' : '') . $v['func']['field'];
00473                                         $output .= isset($v['func']['pos']) ? ', ' . $v['func']['pos'][0] : '';
00474                                         $output .= ')';
00475                                         break;
00476                                 }
00477                             } elseif (isset($v['func']) && $v['func']['type'] === 'IFNULL') {
00478                                 $output .= ' ' . trim($v['modifier']) . ' ';
00479                                 switch (TRUE) {
00480                                     case ($GLOBALS['TYPO3_DB']->runningADOdbDriver('mssql') && $functionMapping):
00481                                         $output .= 'ISNULL';
00482                                         break;
00483                                     case ($GLOBALS['TYPO3_DB']->runningADOdbDriver('oci8') && $functionMapping):
00484                                         $output .= 'NVL';
00485                                         break;
00486                                     default:
00487                                         $output .= 'IFNULL';
00488                                         break;
00489                                 }
00490                                 $output .= '(';
00491                                 $output .= ($v['func']['table'] ? $v['func']['table'] . '.' : '') . $v['func']['field'];
00492                                 $output .= ', ' . $v['func']['default'][1] . $this->compileAddslashes($v['func']['default'][0]) . $v['func']['default'][1];
00493                                 $output .= ')';
00494                             } elseif (isset($v['func']) && $v['func']['type'] === 'FIND_IN_SET') {
00495                                 $output .= ' ' . trim($v['modifier']) . ' ';
00496                                 if ($functionMapping) {
00497                                     switch (TRUE) {
00498                                         case ($GLOBALS['TYPO3_DB']->runningADOdbDriver('mssql')):
00499                                             $field = ($v['func']['table'] ? $v['func']['table'] . '.' : '') . $v['func']['field'];
00500                                             if (!isset($v['func']['str_like'])) {
00501                                                 $v['func']['str_like'] = $v['func']['str'][0];
00502                                             }
00503                                             $output .= '\',\'+' . $field . '+\',\' LIKE \'%,' . $v['func']['str_like'] . ',%\'';
00504                                             break;
00505                                         case ($GLOBALS['TYPO3_DB']->runningADOdbDriver('oci8')):
00506                                             $field = ($v['func']['table'] ? $v['func']['table'] . '.' : '') . $v['func']['field'];
00507                                             if (!isset($v['func']['str_like'])) {
00508                                                 $v['func']['str_like'] = $v['func']['str'][0];
00509                                             }
00510                                             $output .= '\',\'||' . $field . '||\',\' LIKE \'%,' . $v['func']['str_like'] . ',%\'';
00511                                             break;
00512                                         case ($GLOBALS['TYPO3_DB']->runningADOdbDriver('postgres')):
00513                                             $output .= ' FIND_IN_SET(';
00514                                             $output .= $v['func']['str'][1] . $v['func']['str'][0] . $v['func']['str'][1];
00515                                             $output .= ', ' . ($v['func']['table'] ? $v['func']['table'] . '.' : '') . $v['func']['field'];
00516                                             $output .= ') != 0';
00517                                             break;
00518                                         default:
00519                                             $field = ($v['func']['table'] ? $v['func']['table'] . '.' : '') . $v['func']['field'];
00520                                             if (!isset($v['func']['str_like'])) {
00521                                                 $v['func']['str_like'] = $v['func']['str'][0];
00522                                             }
00523                                             $output .= '('
00524                                                     . $field . ' LIKE \'%,' . $v['func']['str_like'] . ',%\''
00525                                                     . ' OR ' . $field . ' LIKE \'' . $v['func']['str_like'] . ',%\''
00526                                                     . ' OR ' . $field . ' LIKE \'%,' . $v['func']['str_like'] . '\''
00527                                                     . ' OR ' . $field . '= ' . $v['func']['str'][1] . $v['func']['str'][0] . $v['func']['str'][1]
00528                                                     . ')';
00529                                             break;
00530                                     }
00531                                 } else /* !$functionMapping */ {
00532                                     switch (TRUE) {
00533                                         case ($GLOBALS['TYPO3_DB']->runningADOdbDriver('mssql')):
00534                                         case ($GLOBALS['TYPO3_DB']->runningADOdbDriver('oci8')):
00535                                         case ($GLOBALS['TYPO3_DB']->runningADOdbDriver('postgres')):
00536                                             $output .= ' FIND_IN_SET(';
00537                                             $output .= $v['func']['str'][1] . $v['func']['str'][0] . $v['func']['str'][1];
00538                                             $output .= ', ' . ($v['func']['table'] ? $v['func']['table'] . '.' : '') . $v['func']['field'];
00539                                             $output .= ')';
00540                                             break;
00541                                         default:
00542                                             $field = ($v['func']['table'] ? $v['func']['table'] . '.' : '') . $v['func']['field'];
00543                                             if (!isset($v['func']['str_like'])) {
00544                                                 $v['func']['str_like'] = $v['func']['str'][0];
00545                                             }
00546                                             $output .= '('
00547                                                     . $field . ' LIKE \'%,' . $v['func']['str_like'] . ',%\''
00548                                                     . ' OR ' . $field . ' LIKE \'' . $v['func']['str_like'] . ',%\''
00549                                                     . ' OR ' . $field . ' LIKE \'%,' . $v['func']['str_like'] . '\''
00550                                                     . ' OR ' . $field . '= ' . $v['func']['str'][1] . $v['func']['str'][0] . $v['func']['str'][1]
00551                                                     . ')';
00552                                             break;
00553                                     }
00554                                 }
00555                             } else {
00556 
00557                                 // Set field/table with modifying prefix if any:
00558                                 $output .= ' ' . trim($v['modifier']) . ' ';
00559 
00560                                 // DBAL-specific: Set calculation, if any:
00561                                 if ($v['calc'] === '&' && $functionMapping) {
00562                                     switch (TRUE) {
00563                                         case $GLOBALS['TYPO3_DB']->runningADOdbDriver('oci8'):
00564                                             // Oracle only knows BITAND(x,y) - sigh
00565                                             $output .= 'BITAND(' . trim(($v['table'] ? $v['table'] . '.' : '') . $v['field']) . ',' . $v['calc_value'][1] . $this->compileAddslashes($v['calc_value'][0]) . $v['calc_value'][1] . ')';
00566                                             break;
00567                                         default:
00568                                             // MySQL, MS SQL Server, PostgreSQL support the &-syntax
00569                                             $output .= trim(($v['table'] ? $v['table'] . '.' : '') . $v['field']) . $v['calc'] . $v['calc_value'][1] . $this->compileAddslashes($v['calc_value'][0]) . $v['calc_value'][1];
00570                                             break;
00571                                     }
00572                                 } elseif ($v['calc']) {
00573                                     $output .= trim(($v['table'] ? $v['table'] . '.' : '') . $v['field']) . $v['calc'];
00574                                     if (isset($v['calc_table'])) {
00575                                         $output .= trim(($v['calc_table'] ? $v['calc_table'] . '.' : '') . $v['calc_field']);
00576                                     } else {
00577                                         $output .= $v['calc_value'][1] . $this->compileAddslashes($v['calc_value'][0]) . $v['calc_value'][1];
00578                                     }
00579                                 } elseif (!($GLOBALS['TYPO3_DB']->runningADOdbDriver('oci8') && preg_match('/(NOT )?LIKE( BINARY)?/', $v['comparator']) && $functionMapping)) {
00580                                     $output .= trim(($v['table'] ? $v['table'] . '.' : '') . $v['field']);
00581                                 }
00582                             }
00583 
00584                             // Set comparator:
00585                             if ($v['comparator']) {
00586                                 $isLikeOperator = preg_match('/(NOT )?LIKE( BINARY)?/', $v['comparator']);
00587                                 switch (TRUE) {
00588                                     case ($GLOBALS['TYPO3_DB']->runningADOdbDriver('oci8') && $isLikeOperator && $functionMapping):
00589                                         // Oracle cannot handle LIKE on CLOB fields - sigh
00590                                         if (isset($v['value']['operator'])) {
00591                                             $values = array();
00592                                             foreach ($v['value']['args'] as $fieldDef) {
00593                                                 $values[] = ($fieldDef['table'] ? $fieldDef['table'] . '.' : '') . $fieldDef['field'];
00594                                             }
00595                                             $compareValue = ' ' . $v['value']['operator'] . '(' . implode(',', $values) . ')';
00596                                         } else {
00597                                             $compareValue = $v['value'][1] . $this->compileAddslashes(trim($v['value'][0], '%')) . $v['value'][1];
00598                                         }
00599                                         if (t3lib_div::isFirstPartOfStr($v['comparator'], 'NOT')) {
00600                                             $output .= 'NOT ';
00601                                         }
00602                                         // To be on the safe side
00603                                         $isLob = TRUE;
00604                                         if ($v['table']) {
00605                                             // Table and field names are quoted:
00606                                             $tableName = substr($v['table'], 1, strlen($v['table']) - 2);
00607                                             $fieldName = substr($v['field'], 1, strlen($v['field']) - 2);
00608                                             $fieldType = $GLOBALS['TYPO3_DB']->sql_field_metatype($tableName, $fieldName);
00609                                             $isLob = ($fieldType === 'B' || $fieldType === 'XL');
00610                                         }
00611                                         if (strtoupper(substr($v['comparator'], -6)) === 'BINARY') {
00612                                             if ($isLob) {
00613                                                 $output .= '(dbms_lob.instr(' . trim(($v['table'] ? $v['table'] . '.' : '') . $v['field']) . ', ' . $compareValue . ',1,1) > 0)';
00614                                             } else {
00615                                                 $output .= '(instr(' . trim(($v['table'] ? $v['table'] . '.' : '') . $v['field']) . ', ' . $compareValue . ',1,1) > 0)';
00616                                             }
00617                                         } else {
00618                                             if ($isLob) {
00619                                                 $output .= '(dbms_lob.instr(LOWER(' . trim(($v['table'] ? $v['table'] . '.' : '') . $v['field']) . '), ' . t3lib_div::strtolower($compareValue) . ',1,1) > 0)';
00620                                             } else {
00621                                                 $output .= '(instr(LOWER(' . trim(($v['table'] ? $v['table'] . '.' : '') . $v['field']) . '), ' . t3lib_div::strtolower($compareValue) . ',1,1) > 0)';
00622                                             }
00623                                         }
00624                                         break;
00625                                     default:
00626                                         if ($isLikeOperator && $functionMapping) {
00627                                             if ($GLOBALS['TYPO3_DB']->runningADOdbDriver('postgres') ||
00628                                                     $GLOBALS['TYPO3_DB']->runningADOdbDriver('postgres64') ||
00629                                                     $GLOBALS['TYPO3_DB']->runningADOdbDriver('postgres7') ||
00630                                                     $GLOBALS['TYPO3_DB']->runningADOdbDriver('postgres8')) {
00631 
00632                                                 // Remap (NOT)? LIKE to (NOT)? ILIKE
00633                                                 // and (NOT)? LIKE BINARY to (NOT)? LIKE
00634                                                 switch ($v['comparator']) {
00635                                                     // Remap (NOT)? LIKE to (NOT)? ILIKE
00636                                                     case 'LIKE':
00637                                                         $v['comparator'] = 'ILIKE';
00638                                                         break;
00639                                                     case 'NOT LIKE':
00640                                                         $v['comparator'] = 'NOT ILIKE';
00641                                                         break;
00642                                                     default:
00643                                                         $v['comparator'] = str_replace(' BINARY', '', $v['comparator']);
00644                                                         break;
00645                                                 }
00646                                             } else {
00647                                                 // No more BINARY operator
00648                                                 $v['comparator'] = str_replace(' BINARY', '', $v['comparator']);
00649                                             }
00650                                         }
00651 
00652                                         $output .= ' ' . $v['comparator'];
00653 
00654                                         // Detecting value type; list or plain:
00655                                         if (t3lib_div::inList('NOTIN,IN', strtoupper(str_replace(array(' ', TAB, CR, LF), '', $v['comparator'])))) {
00656                                             if (isset($v['subquery'])) {
00657                                                 $output .= ' (' . $this->compileSELECT($v['subquery']) . ')';
00658                                             } else {
00659                                                 $valueBuffer = array();
00660                                                 foreach ($v['value'] as $realValue) {
00661                                                     $valueBuffer[] = $realValue[1] . $this->compileAddslashes($realValue[0]) . $realValue[1];
00662                                                 }
00663                                                 $output .= ' (' . trim(implode(',', $valueBuffer)) . ')';
00664                                             }
00665                                         } else if (t3lib_div::inList('BETWEEN,NOT BETWEEN', $v['comparator'])) {
00666                                             $lbound = $v['values'][0];
00667                                             $ubound = $v['values'][1];
00668                                             $output .= ' ' . $lbound[1] . $this->compileAddslashes($lbound[0]) . $lbound[1];
00669                                             $output .= ' AND ';
00670                                             $output .= $ubound[1] . $this->compileAddslashes($ubound[0]) . $ubound[1];
00671                                         } else if (isset($v['value']['operator'])) {
00672                                             $values = array();
00673                                             foreach ($v['value']['args'] as $fieldDef) {
00674                                                 $values[] = ($fieldDef['table'] ? $fieldDef['table'] . '.' : '') . $fieldDef['field'];
00675                                             }
00676                                             $output .= ' ' . $v['value']['operator'] . '(' . implode(',', $values) . ')';
00677                                         } else {
00678                                             $output .= ' ' . $v['value'][1] . $this->compileAddslashes($v['value'][0]) . $v['value'][1];
00679                                         }
00680                                         break;
00681                                 }
00682                             }
00683                         }
00684                     }
00685                 }
00686                 break;
00687         }
00688 
00689         return $output;
00690     }
00691 }
00692 
00693 
00694 if (defined('TYPO3_MODE') && isset($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLASS']['ext/dbal/class.ux_t3lib_sqlparser.php'])) {
00695     include_once($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLASS']['ext/dbal/class.ux_t3lib_sqlparser.php']);
00696 }
00697 
00698 ?>