Documentation TYPO3 par Ameos

class.t3lib_sqlparser.php

00001 <?php
00002 /***************************************************************
00003 *  Copyright notice
00004 *
00005 *  (c) 2004 Kasper Skaarhoj (kasperYYYY@typo3.com)
00006 *  All rights reserved
00007 *
00008 *  This script is part of the TYPO3 project. The TYPO3 project is
00009 *  free software; you can redistribute it and/or modify
00010 *  it under the terms of the GNU General Public License as published by
00011 *  the Free Software Foundation; either version 2 of the License, or
00012 *  (at your option) any later version.
00013 *
00014 *  The GNU General Public License can be found at
00015 *  http://www.gnu.org/copyleft/gpl.html.
00016 *  A copy is found in the textfile GPL.txt and important notices to the license
00017 *  from the author is found in LICENSE.txt distributed with these scripts.
00018 *
00019 *
00020 *  This script is distributed in the hope that it will be useful,
00021 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00022 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00023 *  GNU General Public License for more details.
00024 *
00025 *  This copyright notice MUST APPEAR in all copies of the script!
00026 ***************************************************************/
00106 class t3lib_sqlparser {
00107 
00108                 // Parser:
00109         var $parse_error = '';                                          // Parsing error string
00110         var $lastStopKeyWord = '';                                      // Last stop keyword used.
00111 
00112 
00113 
00114 
00115         /*************************************
00116          *
00117          * SQL Parsing, full queries
00118          *
00119          **************************************/
00120 
00128         function parseSQL($parseString) {
00129 
00130                         // Prepare variables:
00131                 $parseString = $this->trimSQL($parseString);
00132                 $this->parse_error = '';
00133                 $result = array();
00134 
00135                         // Finding starting keyword of string:
00136                 $_parseString = $parseString;   // Protecting original string...
00137                 $keyword = $this->nextPart($_parseString, '^(SELECT|UPDATE|INSERT[[:space:]]+INTO|DELETE[[:space:]]+FROM|EXPLAIN|DROP[[:space:]]+TABLE|CREATE[[:space:]]+TABLE|ALTER[[:space:]]+TABLE)[[:space:]]+');
00138                 $keyword = strtoupper(ereg_replace('[[:space:]]*','',$keyword));
00139 
00140                 switch($keyword)        {
00141                         case 'SELECT':
00142                                         // Parsing SELECT query:
00143                                 $result = $this->parseSELECT($parseString);
00144                         break;
00145                         case 'UPDATE':
00146                                         // Parsing UPDATE query:
00147                                 $result = $this->parseUPDATE($parseString);
00148                         break;
00149                         case 'INSERTINTO':
00150                                         // Parsing INSERT query:
00151                                 $result = $this->parseINSERT($parseString);
00152                         break;
00153                         case 'DELETEFROM':
00154                                         // Parsing DELETE query:
00155                                 $result = $this->parseDELETE($parseString);
00156                         break;
00157                         case 'EXPLAIN':
00158                                         // Parsing EXPLAIN SELECT query:
00159                                 $result = $this->parseEXPLAIN($parseString);
00160                         break;
00161                         case 'DROPTABLE':
00162                                         // Parsing DROP TABLE query:
00163                                 $result = $this->parseDROPTABLE($parseString);
00164                         break;
00165                         case 'ALTERTABLE':
00166                                         // Parsing ALTER TABLE query:
00167                                 $result = $this->parseALTERTABLE($parseString);
00168                         break;
00169                         case 'CREATETABLE':
00170                                         // Parsing CREATE TABLE query:
00171                                 $result = $this->parseCREATETABLE($parseString);
00172                         break;
00173                         default:
00174                                 return $this->parseError('"'.$keyword.'" is not a keyword',$parseString);
00175                         break;
00176                 }
00177 
00178                 return $result;
00179         }
00180 
00188         function parseSELECT($parseString)      {
00189 
00190                         // Removing SELECT:
00191                 $parseString = $this->trimSQL($parseString);
00192                 $parseString = eregi_replace('^SELECT[[:space:]]+','',$parseString);
00193 
00194                         // Init output variable:
00195                 $result = array();
00196                 $result['type'] = 'SELECT';
00197 
00198                         // Looking for STRAIGHT_JOIN keyword:
00199                 $result['STRAIGHT_JOIN'] = $this->nextPart($parseString, '^(STRAIGHT_JOIN)[[:space:]]+');
00200 
00201                         // Select fields:
00202                 $result['SELECT'] = $this->parseFieldList($parseString, '^(FROM)[[:space:]]+');
00203                 if ($this->parse_error) { return $this->parse_error; }
00204 
00205                         // Continue if string is not ended:
00206                 if ($parseString)       {
00207 
00208                                 // Get table list:
00209                         $result['FROM'] = $this->parseFromTables($parseString, '^(WHERE)[[:space:]]+');
00210                         if ($this->parse_error) { return $this->parse_error; }
00211 
00212                                 // If there are more than just the tables (a WHERE clause that would be...)
00213                         if ($parseString)       {
00214 
00215                                         // Get WHERE clause:
00216                                 $result['WHERE'] = $this->parseWhereClause($parseString, '^(GROUP[[:space:]]+BY|ORDER[[:space:]]+BY|LIMIT)[[:space:]]+');
00217                                 if ($this->parse_error) { return $this->parse_error; }
00218 
00219                                         // If the WHERE clause parsing was stopped by GROUP BY, ORDER BY or LIMIT, then proceed with parsing:
00220                                 if ($this->lastStopKeyWord)     {
00221 
00222                                                 // GROUP BY parsing:
00223                                         if ($this->lastStopKeyWord == 'GROUPBY')        {
00224                                                 $result['GROUPBY'] = $this->parseFieldList($parseString, '^(ORDER[[:space:]]+BY|LIMIT)[[:space:]]+');
00225                                                 if ($this->parse_error) { return $this->parse_error; }
00226                                         }
00227 
00228                                                 // ORDER BY parsing:
00229                                         if ($this->lastStopKeyWord == 'ORDERBY')        {
00230                                                 $result['ORDERBY'] = $this->parseFieldList($parseString, '^(LIMIT)[[:space:]]+');
00231                                                 if ($this->parse_error) { return $this->parse_error; }
00232                                         }
00233 
00234                                                 // LIMIT parsing:
00235                                         if ($this->lastStopKeyWord == 'LIMIT')  {
00236                                                 if (ereg('^([0-9]+|[0-9]+[[:space:]]*,[[:space:]]*[0-9]+)$',trim($parseString)))        {
00237                                                         $result['LIMIT'] = $parseString;
00238                                                 } else {
00239                                                         return $this->parseError('No value for limit!',$parseString);
00240                                                 }
00241                                         }
00242                                 }
00243                         }
00244                 } else return $this->parseError('No table to select from!',$parseString);
00245 
00246                         // Return result:
00247                 return $result;
00248         }
00249 
00257         function parseUPDATE($parseString)      {
00258 
00259                         // Removing UPDATE
00260                 $parseString = $this->trimSQL($parseString);
00261                 $parseString = eregi_replace('^UPDATE[[:space:]]+','',$parseString);
00262 
00263                         // Init output variable:
00264                 $result = array();
00265                 $result['type'] = 'UPDATE';
00266 
00267                         // Get table:
00268                 $result['TABLE'] = $this->nextPart($parseString, '^([[:alnum:]_]+)[[:space:]]+');
00269 
00270                         // Continue if string is not ended:
00271                 if ($result['TABLE'])   {
00272                         if ($parseString && $this->nextPart($parseString, '^(SET)[[:space:]]+'))        {
00273 
00274                                 $comma = TRUE;
00275 
00276                                         // Get field/value pairs:
00277                                 while($comma)   {
00278                                         if ($fieldName = $this->nextPart($parseString,'^([[:alnum:]_]+)[[:space:]]*=')) {
00279                                                 $this->nextPart($parseString,'^(=)');   // Strip of "=" sign.
00280                                                 $value = $this->getValue($parseString);
00281                                                 $result['FIELDS'][$fieldName] = $value;
00282                                         } else return $this->parseError('No fieldname found',$parseString);
00283 
00284                                         $comma = $this->nextPart($parseString,'^(,)');
00285                                 }
00286 
00287                                         // WHERE
00288                                 if ($this->nextPart($parseString,'^(WHERE)'))   {
00289                                         $result['WHERE'] = $this->parseWhereClause($parseString);
00290                                         if ($this->parse_error) { return $this->parse_error; }
00291                                 }
00292                         } else return $this->parseError('Query missing SET...',$parseString);
00293                 } else return $this->parseError('No table found!',$parseString);
00294 
00295                         // Should be no more content now:
00296                 if ($parseString)       {
00297                         return $this->parseError('Still content in clause after parsing!',$parseString);
00298                 }
00299 
00300                         // Return result:
00301                 return $result;
00302         }
00303 
00311         function parseINSERT($parseString)      {
00312 
00313                         // Removing INSERT
00314                 $parseString = $this->trimSQL($parseString);
00315                 $parseString = eregi_replace('^INSERT[[:space:]]+INTO[[:space:]]+','',$parseString);
00316 
00317                         // Init output variable:
00318                 $result = array();
00319                 $result['type'] = 'INSERT';
00320 
00321                         // Get table:
00322                 $result['TABLE'] = $this->nextPart($parseString, '^([[:alnum:]_]+)([[:space:]]+|\()');
00323 
00324                 if ($result['TABLE'])   {
00325 
00326                         if ($this->nextPart($parseString,'^(VALUES)[[:space:]]+'))      {       // In this case there are no field names mentioned in the SQL!
00327                                         // Get values/fieldnames (depending...)
00328                                 $result['VALUES_ONLY'] = $this->getValue($parseString,'IN');
00329                                 if ($this->parse_error) { return $this->parse_error; }
00330                         } else {        // There are apparently fieldnames listed:
00331                                 $fieldNames = $this->getValue($parseString,'_LIST');
00332                                 if ($this->parse_error) { return $this->parse_error; }
00333 
00334                                 if ($this->nextPart($parseString,'^(VALUES)[[:space:]]+'))      {       // "VALUES" keyword binds the fieldnames to values:
00335 
00336                                         $values = $this->getValue($parseString,'IN');   // Using the "getValue" function to get the field list...
00337                                         if ($this->parse_error) { return $this->parse_error; }
00338 
00339                                         foreach($fieldNames as $k => $fN)       {
00340                                                 if (ereg('^[[:alnum:]_]+$',$fN))        {
00341                                                         if (isset($values[$k])) {
00342                                                                 if (!isset($result['FIELDS'][$fN]))     {
00343                                                                         $result['FIELDS'][$fN] = $values[$k];
00344                                                                 } else return $this->parseError('Fieldname ("'.$fN.'") already found in list!',$parseString);
00345                                                         } else return $this->parseError('No value set!',$parseString);
00346                                                 } else return $this->parseError('Invalid fieldname ("'.$fN.'")',$parseString);
00347                                         }
00348                                         if (isset($values[$k+1]))       {
00349                                                 return $this->parseError('Too many values in list!',$parseString);
00350                                         }
00351                                 } else return $this->parseError('VALUES keyword expected',$parseString);
00352                         }
00353                 }  else return $this->parseError('No table found!',$parseString);
00354 
00355                         // Should be no more content now:
00356                 if ($parseString)       {
00357                         return $this->parseError('Still content after parsing!',$parseString);
00358                 }
00359 
00360                         // Return result
00361                 return $result;
00362         }
00363 
00371         function parseDELETE($parseString)      {
00372 
00373                         // Removing DELETE
00374                 $parseString = $this->trimSQL($parseString);
00375                 $parseString = eregi_replace('^DELETE[[:space:]]+FROM[[:space:]]+','',$parseString);
00376 
00377                         // Init output variable:
00378                 $result = array();
00379                 $result['type'] = 'DELETE';
00380 
00381                         // Get table:
00382                 $result['TABLE'] = $this->nextPart($parseString, '^([[:alnum:]_]+)[[:space:]]+');
00383 
00384                 if ($result['TABLE'])   {
00385 
00386                                 // WHERE
00387                         if ($this->nextPart($parseString,'^(WHERE)'))   {
00388                                 $result['WHERE'] = $this->parseWhereClause($parseString);
00389                                 if ($this->parse_error) { return $this->parse_error; }
00390                         }
00391                 } else return $this->parseError('No table found!',$parseString);
00392 
00393                         // Should be no more content now:
00394                 if ($parseString)       {
00395                         return $this->parseError('Still content in clause after parsing!',$parseString);
00396                 }
00397 
00398                         // Return result:
00399                 return $result;
00400         }
00401 
00409         function parseEXPLAIN($parseString)     {
00410 
00411                         // Removing EXPLAIN
00412                 $parseString = $this->trimSQL($parseString);
00413                 $parseString = eregi_replace('^EXPLAIN[[:space:]]+','',$parseString);
00414 
00415                         // Init output variable:
00416                 $result = $this->parseSELECT($parseString);
00417                 if (is_array($result))  {
00418                         $result['type'] = 'EXPLAIN';
00419                 }
00420 
00421                 return $result;
00422         }
00423 
00431         function parseCREATETABLE($parseString) {
00432 
00433                         // Removing CREATE TABLE
00434                 $parseString = $this->trimSQL($parseString);
00435                 $parseString = eregi_replace('^CREATE[[:space:]]+TABLE[[:space:]]+','',$parseString);
00436 
00437                         // Init output variable:
00438                 $result = array();
00439                 $result['type'] = 'CREATETABLE';
00440 
00441                         // Get table:
00442                 $result['TABLE'] = $this->nextPart($parseString, '^([[:alnum:]_]+)[[:space:]]*\(',TRUE);
00443 
00444                 if ($result['TABLE'])   {
00445 
00446                                 // While the parseString is not yet empty:
00447                         while(strlen($parseString)>0)   {
00448                                 if ($key = $this->nextPart($parseString, '^(KEY|PRIMARY KEY)([[:space:]]+|\()'))        {       // Getting key
00449                                         $key = strtoupper(ereg_replace('[[:space:]]','',$key));
00450 
00451                                         switch($key)    {
00452                                                 case 'PRIMARYKEY':
00453                                                         $result['KEYS'][$key] = $this->getValue($parseString,'_LIST');
00454                                                         if ($this->parse_error) { return $this->parse_error; }
00455                                                 break;
00456                                                 case 'KEY':
00457                                                         if ($keyName = $this->nextPart($parseString, '^([[:alnum:]_]+)([[:space:]]+|\()'))      {
00458                                                                 $result['KEYS'][$keyName] = $this->getValue($parseString,'_LIST');
00459                                                                 if ($this->parse_error) { return $this->parse_error; }
00460                                                         } else return $this->parseError('No keyname found',$parseString);
00461                                                 break;
00462                                         }
00463                                 } elseif ($fieldName = $this->nextPart($parseString, '^([[:alnum:]_]+)[[:space:]]+'))   {       // Getting field:
00464                                         $result['FIELDS'][$fieldName]['definition'] = $this->parseFieldDef($parseString);
00465                                         if ($this->parse_error) { return $this->parse_error; }
00466                                 }
00467 
00468                                         // Finding delimiter:
00469                                 $delim = $this->nextPart($parseString, '^(,|\))');
00470                                 if (!$delim)    {
00471                                         return $this->parseError('No delimiter found',$parseString);
00472                                 } elseif ($delim==')')  {
00473                                         break;
00474                                 }
00475                         }
00476 
00477                                 // Finding what is after the table definition - table type in MySQL
00478                         if ($delim==')')        {
00479                                 if ($this->nextPart($parseString, '^(TYPE[[:space:]]*=)'))      {
00480                                         $result['tableType'] = $parseString;
00481                                         $parseString = '';
00482                                 }
00483                         } else return $this->parseError('No fieldname found!',$parseString);
00484 
00485                                 // Getting table type
00486                 } else return $this->parseError('No table found!',$parseString);
00487 
00488                         // Should be no more content now:
00489                 if ($parseString)       {
00490                         return $this->parseError('Still content in clause after parsing!',$parseString);
00491                 }
00492 
00493                 return $result;
00494         }
00495 
00503         function parseALTERTABLE($parseString)  {
00504 
00505                         // Removing ALTER TABLE
00506                 $parseString = $this->trimSQL($parseString);
00507                 $parseString = eregi_replace('^ALTER[[:space:]]+TABLE[[:space:]]+','',$parseString);
00508 
00509                         // Init output variable:
00510                 $result = array();
00511                 $result['type'] = 'ALTERTABLE';
00512 
00513                         // Get table:
00514                 $result['TABLE'] = $this->nextPart($parseString, '^([[:alnum:]_]+)[[:space:]]+');
00515 
00516                 if ($result['TABLE'])   {
00517                         if ($result['action'] = $this->nextPart($parseString, '^(CHANGE|DROP[[:space:]]+KEY|DROP[[:space:]]+PRIMARY[[:space:]]+KEY|ADD[[:space:]]+KEY|ADD[[:space:]]+PRIMARY[[:space:]]+KEY|DROP|ADD|RENAME)([[:space:]]+|\()'))        {
00518                                 $actionKey = strtoupper(ereg_replace('[[:space:]]','',$result['action']));
00519 
00520                                         // Getting field:
00521                                 if (t3lib_div::inList('ADDPRIMARYKEY,DROPPRIMARYKEY',$actionKey) || $fieldKey = $this->nextPart($parseString, '^([[:alnum:]_]+)[[:space:]]+'))  {
00522 
00523                                         switch($actionKey)      {
00524                                                 case 'ADD':
00525                                                         $result['FIELD'] = $fieldKey;
00526                                                         $result['definition'] = $this->parseFieldDef($parseString);
00527                                                         if ($this->parse_error) { return $this->parse_error; }
00528                                                 break;
00529                                                 case 'DROP':
00530                                                 case 'RENAME':
00531                                                         $result['FIELD'] = $fieldKey;
00532                                                 break;
00533                                                 case 'CHANGE':
00534                                                         $result['FIELD'] = $fieldKey;
00535                                                         if ($result['newField'] = $this->nextPart($parseString, '^([[:alnum:]_]+)[[:space:]]+'))        {
00536                                                                 $result['definition'] = $this->parseFieldDef($parseString);
00537                                                                 if ($this->parse_error) { return $this->parse_error; }
00538                                                         } else return $this->parseError('No NEW field name found',$parseString);
00539                                                 break;
00540 
00541                                                 case 'ADDKEY':
00542                                                 case 'ADDPRIMARYKEY':
00543                                                         $result['KEY'] = $fieldKey;
00544                                                         $result['fields'] = $this->getValue($parseString,'_LIST');
00545                                                         if ($this->parse_error) { return $this->parse_error; }
00546                                                 break;
00547                                                 case 'DROPKEY':
00548                                                         $result['KEY'] = $fieldKey;
00549                                                 break;
00550                                                 case 'DROPPRIMARYKEY':
00551                                                         // ??? todo!
00552                                                 break;
00553                                         }
00554                                 } else return $this->parseError('No field name found',$parseString);
00555                         } else return $this->parseError('No action CHANGE, DROP or ADD found!',$parseString);
00556                 } else return $this->parseError('No table found!',$parseString);
00557 
00558                         // Should be no more content now:
00559                 if ($parseString)       {
00560                         return $this->parseError('Still content in clause after parsing!',$parseString);
00561                 }
00562 
00563                 return $result;
00564         }
00565 
00572         function parseDROPTABLE($parseString)   {
00573 
00574                         // Removing DROP TABLE
00575                 $parseString = $this->trimSQL($parseString);
00576                 $parseString = eregi_replace('^DROP[[:space:]]+TABLE[[:space:]]+','',$parseString);
00577 
00578                         // Init output variable:
00579                 $result = array();
00580                 $result['type'] = 'DROPTABLE';
00581 
00582                         // IF EXISTS
00583                 $result['ifExists']     = $this->nextPart($parseString, '^(IF[[:space:]]+EXISTS[[:space:]]+)');
00584 
00585                         // Get table:
00586                 $result['TABLE'] = $this->nextPart($parseString, '^([[:alnum:]_]+)[[:space:]]+');
00587 
00588                 if ($result['TABLE'])   {
00589 
00590                                 // Should be no more content now:
00591                         if ($parseString)       {
00592                                 return $this->parseError('Still content in clause after parsing!',$parseString);
00593                         }
00594 
00595                         return $result;
00596                 } else return $this->parseError('No table found!',$parseString);
00597         }
00598 
00599 
00600 
00601 
00602 
00603 
00604 
00605 
00606 
00607 
00608 
00609 
00610 
00611 
00612 
00613 
00614 
00615         /**************************************
00616          *
00617          * SQL Parsing, helper functions for parts of queries
00618          *
00619          **************************************/
00620 
00631         function parseFieldList(&$parseString, $stopRegex='')   {
00632 
00633                         // Prepare variables:
00634                 $parseString = $this->trimSQL($parseString);
00635                 $this->lastStopKeyWord = '';
00636                 $this->parse_error = '';
00637 
00638 
00639                 $stack = array();       // Contains the parsed content
00640                 $pnt = 0;                       // Pointer to positions in $stack
00641                 $level = 0;                     // Indicates the parenthesis level we are at.
00642                 $loopExit = 0;          // Recursivity brake.
00643 
00644                         // $parseString is continously shortend by the process and we keep parsing it till it is zero:
00645                 while (strlen($parseString)) {
00646 
00647                                 // Checking if we are inside / outside parenthesis (in case of a function like count(), max(), min() etc...):
00648                         if ($level>0)   {       // Inside parenthesis here (does NOT detect if values in quotes are used, the only token is ")" or "("):
00649 
00650                                         // Accumulate function content until next () parenthesis:
00651                                 $funcContent = $this->nextPart($parseString,'^([^()]*.)');
00652                                 $stack[$pnt]['func_content.'][] = array(
00653                                         'level' => $level,
00654                                         'func_content' => substr($funcContent,0,-1)
00655                                 );
00656                                 $stack[$pnt]['func_content'].= $funcContent;
00657 
00658                                         // Detecting ( or )
00659                                 switch(substr($stack[$pnt]['func_content'],-1)) {
00660                                         case '(':
00661                                                 $level++;
00662                                         break;
00663                                         case ')':
00664                                                 $level--;
00665                                                 if (!$level)    {       // If this was the last parenthesis:
00666                                                         $stack[$pnt]['func_content'] = substr($stack[$pnt]['func_content'],0,-1);
00667                                                         $parseString = ltrim($parseString);     // Remove any whitespace after the parenthesis.
00668                                                 }
00669                                         break;
00670                                 }
00671                         } else {        // Outside parenthesis, looking for next field:
00672 
00673                                         // Looking for a known function (only known functions supported)
00674                                 $func = $this->nextPart($parseString,'^(count|max|min|floor|sum|avg)[[:space:]]*\(');
00675                                 if ($func)      {
00676                                         $parseString = trim(substr($parseString,1));    // Strip of "("
00677                                         $stack[$pnt]['type'] = 'function';
00678                                         $stack[$pnt]['function'] = $func;
00679                                         $level++;       // increse parenthesis level counter.
00680                                 } else {
00681                                                 // Otherwise, look for regular fieldname:
00682                                         if ($fieldName = $this->nextPart($parseString,'^([[:alnum:]\*._]+)(,|[[:space:]]+)'))   {
00683                                                 $stack[$pnt]['type'] = 'field';
00684 
00685                                                         // Explode fieldname into field and table:
00686                                                 $tableField = explode('.',$fieldName,2);
00687                                                 if (count($tableField)==2)      {
00688                                                         $stack[$pnt]['table'] = $tableField[0];
00689                                                         $stack[$pnt]['field'] = $tableField[1];
00690                                                 } else {
00691                                                         $stack[$pnt]['table'] = '';
00692                                                         $stack[$pnt]['field'] = $tableField[0];
00693                                                 }
00694                                         } else {
00695                                                 return $this->parseError('No field name found as expected',$parseString);
00696                                         }
00697                                 }
00698                         }
00699 
00700                                 // After a function or field we look for "AS" alias and a comma to separate to the next field in the list:
00701                         if (!$level)    {
00702 
00703                                         // Looking for "AS" alias:
00704                                 if ($as = $this->nextPart($parseString,'^(AS)[[:space:]]+'))    {
00705                                         $stack[$pnt]['as'] = $this->nextPart($parseString,'^([[:alnum:]_]+)(,|[[:space:]]+)');
00706                                         $stack[$pnt]['as_keyword'] = $as;
00707                                 }
00708 
00709                                         // Looking for "ASC" or "DESC" keywords (for ORDER BY)
00710                                 if ($sDir = $this->nextPart($parseString,'^(ASC|DESC)([[:space:]]+|,)'))        {
00711                                         $stack[$pnt]['sortDir'] = $sDir;
00712                                 }
00713 
00714                                         // Looking for stop-keywords:
00715                                 if ($stopRegex && $this->lastStopKeyWord = $this->nextPart($parseString, $stopRegex))   {
00716                                         $this->lastStopKeyWord = strtoupper(ereg_replace('[[:space:]]*','',$this->lastStopKeyWord));
00717                                         return $stack;
00718                                 }
00719 
00720                                         // Looking for comma (since the stop-keyword did not trigger a return...)
00721                                 if (strlen($parseString) && !$this->nextPart($parseString,'^(,)'))      {
00722                                         return $this->parseError('No comma found as expected',$parseString);
00723                                 }
00724 
00725                                         // Increasing pointer:
00726                                 $pnt++;
00727                         }
00728 
00729                                 // Check recursivity brake:
00730                         $loopExit++;
00731                         if ($loopExit>500)      {
00732                                 return $this->parseError('More than 500 loops, exiting prematurely...',$parseString);
00733                         }
00734                 }
00735 
00736                         // Return result array:
00737                 return $stack;
00738         }
00739 
00749         function parseFromTables(&$parseString, $stopRegex='')  {
00750 
00751                         // Prepare variables:
00752                 $parseString = $this->trimSQL($parseString);
00753                 $this->lastStopKeyWord = '';
00754                 $this->parse_error = '';
00755 
00756                 $stack = array();       // Contains the parsed content
00757                 $pnt = 0;                       // Pointer to positions in $stack
00758                 $loopExit = 0;          // Recursivity brake.
00759 
00760                         // $parseString is continously shortend by the process and we keep parsing it till it is zero:
00761                 while (strlen($parseString)) {
00762 
00763                                 // Looking for the table:
00764                         if ($stack[$pnt]['table'] = $this->nextPart($parseString,'^([[:alnum:]_]+)(,|[[:space:]]+)'))   {
00765                                 if ($as = $this->nextPart($parseString,'^(AS)[[:space:]]+'))    {
00766                                         $stack[$pnt]['as'] = $this->nextPart($parseString,'^([[:alnum:]_]+)(,|[[:space:]]+)');
00767                                         $stack[$pnt]['as_keyword'] = $as;
00768                                 }
00769                         } else return $this->parseError('No table name found as expected!',$parseString);
00770 
00771                                 // Looking for JOIN
00772                         if ($join = $this->nextPart($parseString,'^(JOIN|LEFT[[:space:]]+JOIN)[[:space:]]+'))   {
00773                                 $stack[$pnt]['JOIN']['type'] = $join;
00774                                 if ($stack[$pnt]['JOIN']['withTable'] = $this->nextPart($parseString,'^([[:alnum:]_]+)[[:space:]]+ON[[:space:]]+',1))   {
00775                                         $field1 = $this->nextPart($parseString,'^([[:alnum:]_.]+)[[:space:]]*=[[:space:]]*',1);
00776                                         $field2 = $this->nextPart($parseString,'^([[:alnum:]_.]+)[[:space:]]+');
00777                                         if ($field1 && $field2) {
00778                                                 $stack[$pnt]['JOIN']['ON'] = array($field1,$field2);
00779                                         } else return $this->parseError('No join fields found!',$parseString);
00780                                 } else  return $this->parseError('No join table found!',$parseString);
00781                         }
00782 
00783                                 // Looking for stop-keywords:
00784                         if ($stopRegex && $this->lastStopKeyWord = $this->nextPart($parseString, $stopRegex))   {
00785                                 $this->lastStopKeyWord = strtoupper(ereg_replace('[[:space:]]*','',$this->lastStopKeyWord));
00786                                 return $stack;
00787                         }
00788 
00789                                 // Looking for comma:
00790                         if (strlen($parseString) && !$this->nextPart($parseString,'^(,)'))      {
00791                                 return $this->parseError('No comma found as expected',$parseString);
00792                         }
00793 
00794                                 // Increasing pointer:
00795                         $pnt++;
00796 
00797                                 // Check recursivity brake:
00798                         $loopExit++;
00799                         if ($loopExit>500)      {
00800                                 return $this->parseError('More than 500 loops, exiting prematurely...',$parseString);
00801                         }
00802                 }
00803 
00804                         // Return result array:
00805                 return $stack;
00806         }
00807 
00816         function parseWhereClause(&$parseString, $stopRegex='') {
00817 
00818                         // Prepare variables:
00819                 $parseString = $this->trimSQL($parseString);
00820                 $this->lastStopKeyWord = '';
00821                 $this->parse_error = '';
00822 
00823                 $stack = array(0 => array());   // Contains the parsed content
00824                 $pnt = array(0 => 0);                   // Pointer to positions in $stack
00825                 $level = 0;                                             // Determines parenthesis level
00826                 $loopExit = 0;                                  // Recursivity brake.
00827 
00828                         // $parseString is continously shortend by the process and we keep parsing it till it is zero:
00829                 while (strlen($parseString)) {
00830 
00831                                 // Look for next parenthesis level:
00832                         $newLevel = $this->nextPart($parseString,'^([(])');
00833                         if ($newLevel=='(')     {                       // If new level is started, manage stack/pointers:
00834                                 $level++;                                       // Increase level
00835                                 $pnt[$level] = 0;                       // Reset pointer for this level
00836                                 $stack[$level] = array();       // Reset stack for this level
00837                         } else {        // If no new level is started, just parse the current level:
00838 
00839                                         // Find "modifyer", eg. "NOT or !"
00840                                 $stack[$level][$pnt[$level]]['modifier'] = trim($this->nextPart($parseString,'^(!|NOT[[:space:]]+)'));
00841 
00842                                         // Fieldname:
00843                                 if ($fieldName = $this->nextPart($parseString,'^([[:alnum:]._]+)([[:space:]]+|&|<=|>=|<|>|=|!=|IS)'))   {
00844 
00845                                                 // Parse field name into field and table:
00846                                         $tableField = explode('.',$fieldName,2);
00847                                         if (count($tableField)==2)      {
00848                                                 $stack[$level][$pnt[$level]]['table'] = $tableField[0];
00849                                                 $stack[$level][$pnt[$level]]['field'] = $tableField[1];
00850                                         } else {
00851                                                 $stack[$level][$pnt[$level]]['table'] = '';
00852                                                 $stack[$level][$pnt[$level]]['field'] = $tableField[0];
00853                                         }
00854                                 } else {
00855                                         return $this->parseError('No field name found as expected',$parseString);
00856                                 }
00857 
00858                                         // See if the value is calculated. Support only for "&" (boolean AND) at the moment:
00859                                 $stack[$level][$pnt[$level]]['calc'] = $this->nextPart($parseString,'^(&)');
00860                                 if (strlen($stack[$level][$pnt[$level]]['calc']))       {
00861                                                 // Finding value for calculation:
00862                                         $stack[$level][$pnt[$level]]['calc_value'] = $this->getValue($parseString);
00863                                 }
00864 
00865                                         // Find "comparator":
00866                                 $stack[$level][$pnt[$level]]['comparator'] = $this->nextPart($parseString,'^(<=|>=|<|>|=|!=|NOT[[:space:]]+IN|IN|NOT[[:space:]]+LIKE|LIKE|IS)');
00867                                 if (strlen($stack[$level][$pnt[$level]]['comparator'])) {
00868                                                 // Finding value for comparator:
00869                                         $stack[$level][$pnt[$level]]['value'] = $this->getValue($parseString,$stack[$level][$pnt[$level]]['comparator']);
00870                                         if ($this->parse_error) { return $this->parse_error; }
00871                                 }
00872 
00873                                         // Finished, increase pointer:
00874                                 $pnt[$level]++;
00875 
00876                                         // Checking if the current level is ended, in that case do stack management:
00877                                 while ($this->nextPart($parseString,'^([)])'))  {
00878                                         $level--;               // Decrease level:
00879                                         $stack[$level][$pnt[$level]]['sub'] = $stack[$level+1];         // Copy stack
00880                                         $pnt[$level]++; // Increase pointer of the new level
00881 
00882                                                 // Make recursivity check:
00883                                         $loopExit++;
00884                                         if ($loopExit>500)      {
00885                                                 return $this->parseError('More than 500 loops (in search for exit parenthesis), exiting prematurely...',$parseString);
00886                                         }
00887                                 }
00888 
00889                                         // Detecting the operator for the next level; support for AND, OR and &&):
00890                                 $op = $this->nextPart($parseString,'^(AND|OR|AND[[:space:]]+NOT)(\(|[[:space:]]+)');
00891                                 if ($op)        {
00892                                         $stack[$level][$pnt[$level]]['operator'] = $op;
00893                                 } elseif (strlen($parseString)) {
00894 
00895                                                 // Looking for stop-keywords:
00896                                         if ($stopRegex && $this->lastStopKeyWord = $this->nextPart($parseString, $stopRegex))   {
00897                                                 $this->lastStopKeyWord = strtoupper(ereg_replace('[[:space:]]*','',$this->lastStopKeyWord));
00898                                                 return $stack[0];
00899                                         } else {
00900                                                 return $this->parseError('No operator, but parsing not finished.',$parseString);
00901                                         }
00902                                 }
00903                         }
00904 
00905                                 // Make recursivity check:
00906                         $loopExit++;
00907                         if ($loopExit>500)      {
00908                                 return $this->parseError('More than 500 loops, exiting prematurely...',$parseString);
00909                         }
00910                 }
00911 
00912                         // Return the stacks lowest level:
00913                 return $stack[0];
00914         }
00915 
00924         function parseFieldDef(&$parseString, $stopRegex='')    {
00925                         // Prepare variables:
00926                 $parseString = $this->trimSQL($parseString);
00927                 $this->lastStopKeyWord = '';
00928                 $this->parse_error = '';
00929 
00930                 $result = array();
00931 
00932                         // Field type:
00933                 if ($result['fieldType'] =  $this->nextPart($parseString,'^(int|smallint|tinyint|mediumint|double|varchar|char|text|tinytext|mediumtext|blob|tinyblob|mediumblob|longblob)([[:space:]]+|\()'))  {
00934 
00935                                 // Looking for value:
00936                         if (substr($parseString,0,1)=='(')      {
00937                                 $parseString = substr($parseString,1);
00938                                 if ($result['value'] =  $this->nextPart($parseString,'^([^)]*)'))       {
00939                                         $parseString = ltrim(substr($parseString,1));
00940                                 } else return $this->parseError('No end-parenthesis for value found!',$parseString);
00941                         }
00942 
00943                                 // Looking for keywords
00944                         while($keyword = $this->nextPart($parseString,'^(DEFAULT|NOT[[:space:]]+NULL|AUTO_INCREMENT|UNSIGNED)([[:space:]]+|,|\))'))     {
00945                                 $keywordCmp = strtoupper(ereg_replace('[[:space:]]*','',$keyword));
00946 
00947                                 $result['featureIndex'][$keywordCmp]['keyword'] = $keyword;
00948 
00949                                 switch($keywordCmp)     {
00950                                         case 'DEFAULT':
00951                                                 $result['featureIndex'][$keywordCmp]['value'] = $this->getValue($parseString);
00952                                         break;
00953                                 }
00954                         }
00955                 } else return $this->parseError('Field type unknown!',$parseString);
00956 
00957                 return $result;
00958         }
00959 
00960 
00961 
00962 
00963 
00964 
00965 
00966 
00967 
00968 
00969 
00970         /************************************
00971          *
00972          * Parsing: Helper functions
00973          *
00974          ************************************/
00975 
00985         function nextPart(&$parseString,$regex,$trimAll=FALSE)  {
00986                 if (eregi($regex,$parseString.' ', $reg))       {       // Adding space char because [[:space:]]+ is often a requirement in regex's
00987                         $parseString = ltrim(substr($parseString,strlen($reg[$trimAll?0:1])));
00988                         return $reg[1];
00989                 }
00990         }
00991 
00999         function getValue(&$parseString,$comparator='') {
01000                 if (t3lib_div::inList('NOTIN,IN,_LIST',strtoupper(ereg_replace('[[:space:]]','',$comparator)))) {       // List of values:
01001                         if ($this->nextPart($parseString,'^([(])'))     {
01002                                 $listValues = array();
01003                                 $comma=',';
01004 
01005                                 while($comma==',')      {
01006                                         $listValues[] = $this->getValue($parseString);
01007                                         $comma = $this->nextPart($parseString,'^([,])');
01008                                 }
01009 
01010                                 $out = $this->nextPart($parseString,'^([)])');
01011                                 if ($out)       {
01012                                         if ($comparator=='_LIST')       {
01013                                                 $kVals = array();
01014                                                 foreach ($listValues as $vArr)  {
01015                                                         $kVals[] = $vArr[0];
01016                                                 }
01017                                                 return $kVals;
01018                                         } else {
01019                                                 return $listValues;
01020                                         }
01021                                 } else return array($this->parseError('No ) parenthesis in list',$parseString));
01022                         } else return array($this->parseError('No ( parenthesis starting the list',$parseString));
01023 
01024                 } else {        // Just plain string value, in quotes or not:
01025 
01026                                 // Quote?
01027                         $firstChar = substr($parseString,0,1);
01028 
01029                         switch($firstChar)      {
01030                                 case '"':
01031                                         return array($this->getValueInQuotes($parseString,'"'),'"');
01032                                 break;
01033                                 case "'":
01034                                         return array($this->getValueInQuotes($parseString,"'"),"'");
01035                                 break;
01036                                 default:
01037                                         if (eregi('^([[:alnum:]._-]+)',$parseString, $reg))     {
01038                                                 $parseString = ltrim(substr($parseString,strlen($reg[0])));
01039                                                 return array($reg[1]);
01040                                         }
01041                                 break;
01042                         }
01043                 }
01044         }
01045 
01054         function getValueInQuotes(&$parseString,$quote) {
01055 
01056                 $parts = explode($quote,substr($parseString,1));
01057                 $buffer = '';
01058                 foreach($parts as $k => $v)     {
01059                         $buffer.=$v;
01060 
01061                         unset($reg);
01062                         ereg('[\]*$',$v,$reg);
01063                         if (strlen($reg[0])%2)  {
01064                                 $buffer.=$quote;
01065                         } else {
01066                                 $parseString = ltrim(substr($parseString,strlen($buffer)+2));
01067                                 return $this->parseStripslashes($buffer);
01068                         }
01069                 }
01070         }
01071 
01079         function parseStripslashes($str)        {
01080                 $search = array('\\\\', '\\\'', '\\"', '\0', '\n', '\r', '\Z');
01081                 $replace = array('\\', '\'', '"', "\x00", "\x0a", "\x0d", "\x1a");
01082 
01083                 return str_replace($search, $replace, $str);
01084         }
01085 
01093         function compileAddslashes($str)        {
01094                 $search = array('\\', '\'', '"', "\x00", "\x0a", "\x0d", "\x1a");
01095                 $replace = array('\\\\', '\\\'', '\\"', '\0', '\n', '\r', '\Z');
01096 
01097                 return str_replace($search, $replace, $str);
01098         }
01099 
01107         function parseError($msg,$restQuery)    {
01108                 $this->parse_error = 'SQL engine parse ERROR: '.$msg.': near "'.substr($restQuery,0,50).'"';
01109                 return $this->parse_error;
01110         }
01111 
01121         function trimSQL($str)  {
01122                 return trim(ereg_replace('[[:space:];]*$','',$str)).' ';
01123         }
01124 
01125 
01126 
01127 
01128 
01129 
01130 
01131 
01132 
01133 
01134 
01135 
01136         /*************************
01137          *
01138          * Compiling queries
01139          *
01140          *************************/
01141 
01149         function compileSQL($components)        {
01150                 switch($components['type'])     {
01151                         case 'SELECT':
01152                                 $query = $this->compileSELECT($components);
01153                         break;
01154                         case 'UPDATE':
01155                                 $query = $this->compileUPDATE($components);
01156                         break;
01157                         case 'INSERT':
01158                                 $query = $this->compileINSERT($components);
01159                         break;
01160                         case 'DELETE':
01161                                 $query = $this->compileDELETE($components);
01162                         break;
01163                         case 'EXPLAIN':
01164                                 $query = 'EXPLAIN '.$this->compileSELECT($components);
01165                         break;
01166                         case 'DROPTABLE':
01167                                 $query = 'DROP TABLE'.($components['ifExists']?' IF EXISTS':'').' '.$components['TABLE'];
01168                         break;
01169                         case 'CREATETABLE':
01170                                 $query = $this->compileCREATETABLE($components);
01171                         break;
01172                         case 'ALTERTABLE':
01173                                 $query = $this->compileALTERTABLE($components);
01174                         break;
01175                 }
01176 
01177                 return $query;
01178         }
01179 
01187         function compileSELECT($components)     {
01188 
01189                         // Initialize:
01190                 $where = $this->compileWhereClause($components['WHERE']);
01191                 $groupBy = $this->compileFieldList($components['GROUPBY']);
01192                 $orderBy = $this->compileFieldList($components['ORDERBY']);
01193                 $limit = $components['LIMIT'];
01194 
01195                         // Make query:
01196                 $query = 'SELECT '.($components['STRAIGHT_JOIN'] ? $components['STRAIGHT_JOIN'].'' : '').'
01197                                 '.$this->compileFieldList($components['SELECT']).'
01198                                 FROM '.$this->compileFromTables($components['FROM']).
01199                                         (strlen($where)?'
01200                                 WHERE '.$where : '').
01201                                         (strlen($groupBy)?'
01202                                 GROUP BY '.$groupBy : '').
01203                                         (strlen($orderBy)?'
01204                                 ORDER BY '.$orderBy : '').
01205                                         (strlen($limit)?'
01206                                 LIMIT '.$limit : '');
01207 
01208                 return $query;
01209         }
01210 
01218         function compileUPDATE($components)     {
01219 
01220                         // Where clause:
01221                 $where = $this->compileWhereClause($components['WHERE']);
01222 
01223                         // Fields
01224                 $fields = array();
01225                 foreach($components['FIELDS'] as $fN => $fV)    {
01226                         $fields[]=$fN.'='.$fV[1].$this->compileAddslashes($fV[0]).$fV[1];
01227                 }
01228 
01229                         // Make query:
01230                 $query = 'UPDATE '.$components['TABLE'].' SET
01231                                 '.implode(',
01232                                 ',$fields).'
01233                                 '.(strlen($where)?'
01234                                 WHERE '.$where : '');
01235 
01236                 return $query;
01237         }
01238 
01246         function compileINSERT($components)     {
01247 
01248                 if ($components['VALUES_ONLY']) {
01249                                 // Initialize:
01250                         $fields = array();
01251                         foreach($components['VALUES_ONLY'] as $fV)      {
01252                                 $fields[]=$fV[1].$this->compileAddslashes($fV[0]).$fV[1];
01253                         }
01254 
01255                                 // Make query:
01256                         $query = 'INSERT INTO '.$components['TABLE'].'
01257                                         VALUES
01258                                         ('.implode(',
01259                                         ',$fields).')';
01260                 } else {
01261                                 // Initialize:
01262                         $fields = array();
01263                         foreach($components['FIELDS'] as $fN => $fV)    {
01264                                 $fields[$fN]=$fV[1].$this->compileAddslashes($fV[0]).$fV[1];
01265                         }
01266 
01267                                 // Make query:
01268                         $query = 'INSERT INTO '.$components['TABLE'].'
01269                                         ('.implode(',
01270                                         ',array_keys($fields)).')
01271                                         VALUES
01272                                         ('.implode(',
01273                                         ',$fields).')';
01274                 }
01275 
01276                 return $query;
01277         }
01278 
01286         function compileDELETE($components)     {
01287 
01288                         // Where clause:
01289                 $where = $this->compileWhereClause($components['WHERE']);
01290 
01291                         // Make query:
01292                 $query = 'DELETE FROM '.$components['TABLE'].
01293                                 (strlen($where)?'
01294                                 WHERE '.$where : '');
01295 
01296                 return $query;
01297         }
01298 
01306         function compileCREATETABLE($components)        {
01307 
01308                         // Create fields and keys:
01309                 $fieldsKeys = array();
01310                 foreach($components['FIELDS'] as $fN => $fCfg)  {
01311                         $fieldsKeys[]=$fN.' '.$this->compileFieldCfg($fCfg['definition']);
01312                 }
01313                 foreach($components['KEYS'] as $kN => $kCfg)    {
01314                         if ($kN == 'PRIMARYKEY')        {
01315                                 $fieldsKeys[]='PRIMARY KEY ('.implode(',', $kCfg).')';
01316                         } else {
01317                                 $fieldsKeys[]='KEY '.$kN.' ('.implode(',', $kCfg).')';
01318                         }
01319                 }
01320 
01321                         // Make query:
01322                 $query = 'CREATE TABLE '.$components['TABLE'].' (
01323                         '.implode(',
01324                         ', $fieldsKeys).'
01325                         )'.($components['tableType'] ? ' TYPE='.$components['tableType'] : '');
01326 
01327                 return $query;
01328         }
01329 
01337         function compileALTERTABLE($components) {
01338 
01339                         // Make query:
01340                 $query = 'ALTER TABLE '.$components['TABLE'].' '.$components['action'].' '.($components['FIELD']?$components['FIELD']:$components['KEY']);
01341 
01342                         // Based on action, add the final part:
01343                 switch(strtoupper(ereg_replace('[[:space:]]','',$components['action'])))        {
01344                         case 'ADD':
01345                                 $query.=' '.$this->compileFieldCfg($components['definition']);
01346                         break;
01347                         case 'CHANGE':
01348                                 $query.=' '.$components['newField'].' '.$this->compileFieldCfg($components['definition']);
01349                         break;
01350                         case 'DROP':
01351                         case 'DROPKEY':
01352                         break;
01353                         case 'ADDKEY':
01354                         case 'ADDPRIMARYKEY':
01355                                 $query.=' ('.implode(',',$components['fields']).')';
01356                         break;
01357                 }
01358 
01359                         // Return query
01360                 return $query;
01361         }
01362 
01363 
01364 
01365 
01366 
01367 
01368 
01369 
01370 
01371 
01372 
01373 
01374 
01375 
01376         /**************************************
01377          *
01378          * Compiling queries, helper functions for parts of queries
01379          *
01380          **************************************/
01381 
01390         function compileFieldList($selectFields)        {
01391 
01392                         // Prepare buffer variable:
01393                 $outputParts = array();
01394 
01395                         // Traverse the selectFields if any:
01396                 if (is_array($selectFields))    {
01397                         foreach($selectFields as $k => $v)      {
01398 
01399                                         // Detecting type:
01400                                 switch($v['type'])      {
01401                                         case 'function':
01402                                                 $outputParts[$k] = $v['function'].'('.$v['func_content'].')';
01403                                         break;
01404                                         case 'field':
01405                                                 $outputParts[$k] = ($v['table']?$v['table'].'.':'').$v['field'];
01406                                         break;
01407                                 }
01408 
01409                                         // Alias:
01410                                 if ($v['as'])   {
01411                                         $outputParts[$k].= ' '.$v['as_keyword'].' '.$v['as'];
01412                                 }
01413 
01414                                         // Specifically for ORDER BY and GROUP BY field lists:
01415                                 if ($v['sortDir'])      {
01416                                         $outputParts[$k].= ' '.$v['sortDir'];
01417                                 }
01418                         }
01419                 }
01420 
01421                         // Return imploded buffer:
01422                 return implode(', ',$outputParts);
01423         }
01424 
01432         function compileFromTables($tablesArray)        {
01433 
01434                         // Prepare buffer variable:
01435                 $outputParts = array();
01436 
01437                         // Traverse the table names:
01438                 if (is_array($tablesArray))     {
01439                         foreach($tablesArray as $k => $v)       {
01440 
01441                                         // Set table name:
01442                                 $outputParts[$k] = $v['table'];
01443 
01444                                         // Add alias AS if there:
01445                                 if ($v['as'])   {
01446                                         $outputParts[$k].= ' '.$v['as_keyword'].' '.$v['as'];
01447                                 }
01448 
01449                                 if (is_array($v['JOIN']))       {
01450                                         $outputParts[$k].= ' '.$v['JOIN']['type'].' '.$v['JOIN']['withTable'].' ON '.implode('=',$v['JOIN']['ON']);
01451                                 }
01452 
01453                         }
01454                 }
01455 
01456                         // Return imploded buffer:
01457                 return implode(', ',$outputParts);
01458         }
01459 
01468         function compileWhereClause($clauseArray)       {
01469 
01470                         // Prepare buffer variable:
01471                 $output='';
01472 
01473                         // Traverse clause array:
01474                 if (is_array($clauseArray))     {
01475                         foreach($clauseArray as $k => $v)       {
01476 
01477                                         // Set operator:
01478                                 $output.=$v['operator'] ? ' '.$v['operator'] : '';
01479 
01480                                         // Look for sublevel:
01481                                 if (is_array($v['sub']))        {
01482                                         $output.=' ('.trim($this->compileWhereClause($v['sub'])).')';
01483                                 } else {
01484 
01485                                                 // Set field/table with modifying prefix if any:
01486                                         $output.=' '.trim($v['modifier'].' '.($v['table']?$v['table'].'.':'').$v['field']);
01487 
01488                                                 // Set calculation, if any:
01489                                         if ($v['calc']) {
01490                                                 $output.=$v['calc'].$v['calc_value'][1].$this->compileAddslashes($v['calc_value'][0]).$v['calc_value'][1];
01491                                         }
01492 
01493                                                 // Set comparator:
01494                                         if ($v['comparator'])   {
01495                                                 $output.=' '.$v['comparator'];
01496 
01497                                                         // Detecting value type; list or plain:
01498                                                 if (t3lib_div::inList('NOTIN,IN',strtoupper(ereg_replace('[[:space:]]','',$v['comparator']))))  {
01499                                                         $valueBuffer = array();
01500                                                         foreach($v['value'] as $realValue)      {
01501                                                                 $valueBuffer[]=$realValue[1].$this->compileAddslashes($realValue[0]).$realValue[1];
01502                                                         }
01503                                                         $output.=' ('.trim(implode(',',$valueBuffer)).')';
01504                                                 } else {
01505                                                         $output.=' '.$v['value'][1].$this->compileAddslashes($v['value'][0]).$v['value'][1];
01506                                                 }
01507                                         }
01508                                 }
01509                         }
01510                 }
01511 
01512                         // Return output buffer:
01513                 return $output;
01514         }
01515 
01522         function compileFieldCfg($fieldCfg)     {
01523 
01524                         // Set type:
01525                 $cfg = $fieldCfg['fieldType'];
01526 
01527                         // Add value, if any:
01528                 if (strlen($fieldCfg['value'])) {
01529                         $cfg.='('.$fieldCfg['value'].')';
01530                 }
01531 
01532                         // Add additional features:
01533                 if (is_array($fieldCfg['featureIndex']))        {
01534                         foreach($fieldCfg['featureIndex'] as $featureDef)       {
01535                                 $cfg.=' '.$featureDef['keyword'];
01536 
01537                                         // Add value if found:
01538                                 if (is_array($featureDef['value']))     {
01539                                         $cfg.=' '.$featureDef['value'][1].$this->compileAddslashes($featureDef['value'][0]).$featureDef['value'][1];
01540                                 }
01541                         }
01542                 }
01543 
01544                         // Return field definition string:
01545                 return $cfg;
01546         }
01547 
01548 
01549 
01550 
01551 
01552 
01553 
01554 
01555 
01556 
01557 
01558         /*************************
01559          *
01560          * Debugging
01561          *
01562          *************************/
01563 
01571         function debug_parseSQLpart($part,$str) {
01572                 switch($part)   {
01573                         case 'SELECT':
01574                                 return $this->debug_parseSQLpartCompare($str,$this->compileFieldList($this->parseFieldList($str)));
01575                         break;
01576                         case 'FROM':
01577                                 return $this->debug_parseSQLpartCompare($str,$this->compileFromTables($this->parseFromTables($str)));
01578                         break;
01579                         case 'WHERE':
01580                                 return $this->debug_parseSQLpartCompare($str,$this->compileWhereClause($this->parseWhereClause($str)));
01581                         break;
01582                 }
01583         }
01584 
01593         function debug_parseSQLpartCompare($str,$newStr,$caseInsensitive=FALSE) {
01594                 if ($caseInsensitive)   {
01595                         $str1 = strtoupper($str);
01596                         $str2 = strtoupper($newStr);
01597                 } else {
01598                         $str1 = $str;
01599                         $str2 = $newStr;
01600                 }
01601 
01602                         // Fixing escaped chars:
01603                 $search = array('\0', '\n', '\r', '\Z');
01604                 $replace = array("\x00", "\x0a", "\x0d", "\x1a");
01605                 $str1 = str_replace($search, $replace, $str1);
01606                 $str2 = str_replace($search, $replace, $str2);
01607 
01608                         # Normally, commented out since they are needed only in tricky cases...
01609 #               $str1 = stripslashes($str1);
01610 #               $str2 = stripslashes($str2);
01611 
01612                 if (strcmp(ereg_replace('[[:space:]]','',$this->trimSQL($str1)),ereg_replace('[[:space:]]','',$this->trimSQL($str2))))  {
01613                         return array(
01614                                         ereg_replace('[[:space:]]+',' ',$str),
01615                                         ereg_replace('[[:space:]]+',' ',$newStr),
01616                                 );
01617                 }
01618         }
01619 
01626         function debug_testSQL($SQLquery)       {
01627 #               return $SQLquery;
01628 #debug(array($SQLquery));
01629 
01630                         // Getting result array:
01631                 $parseResult = $this->parseSQL($SQLquery);
01632 
01633                         // If result array was returned, proceed. Otherwise show error and exit.
01634                 if (is_array($parseResult))     {
01635 
01636                                 // Re-compile query:
01637                         $newQuery = $this->compileSQL($parseResult);
01638 
01639                                 // TEST the new query:
01640                         $testResult = $this->debug_parseSQLpartCompare($SQLquery, $newQuery);
01641 
01642                                 // Return new query if OK, otherwise show error and exit:
01643                         if (!is_array($testResult))     {
01644                                 return $newQuery;
01645                         } else {
01646                                 debug(array('ERROR MESSAGE'=>'Input query did not match the parsed and recompiled query exactly (not observing whitespace)', 'TEST result' => $testResult),'SQL parsing failed:');
01647                                 exit;
01648                         }
01649                 } else {
01650                         debug(array('query' => $SQLquery, 'ERROR MESSAGE'=>$parseResult),'SQL parsing failed:');
01651                         exit;
01652                 }
01653         }
01654 }
01655 
01656 
01657 if (defined('TYPO3_MODE') && $TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['t3lib/class.t3lib_sqlparser.php']) {
01658         include_once($TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['t3lib/class.t3lib_sqlparser.php']);
01659 }
01660 ?>


Généré par Les experts TYPO3 avec  doxygen 1.4.6