Documentation TYPO3 par Ameos |
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 ?>