00001 <?php
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00107 class t3lib_sqlparser {
00108
00109
00110 var $parse_error = '';
00111 var $lastStopKeyWord = '';
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00129 function parseSQL($parseString) {
00130
00131 $parseString = $this->trimSQL($parseString);
00132 $this->parse_error = '';
00133 $result = array();
00134
00135
00136 $_parseString = $parseString;
00137 $keyword = $this->nextPart($_parseString, '^(SELECT|UPDATE|INSERT[[:space:]]+INTO|DELETE[[:space:]]+FROM|EXPLAIN|DROP[[:space:]]+TABLE|CREATE[[:space:]]+TABLE|CREATE[[:space:]]+DATABASE|ALTER[[:space:]]+TABLE)[[:space:]]+');
00138 $keyword = strtoupper(str_replace(array(' ',"\t","\r","\n"),'',$keyword));
00139
00140 switch($keyword) {
00141 case 'SELECT':
00142
00143 $result = $this->parseSELECT($parseString);
00144 break;
00145 case 'UPDATE':
00146
00147 $result = $this->parseUPDATE($parseString);
00148 break;
00149 case 'INSERTINTO':
00150
00151 $result = $this->parseINSERT($parseString);
00152 break;
00153 case 'DELETEFROM':
00154
00155 $result = $this->parseDELETE($parseString);
00156 break;
00157 case 'EXPLAIN':
00158
00159 $result = $this->parseEXPLAIN($parseString);
00160 break;
00161 case 'DROPTABLE':
00162
00163 $result = $this->parseDROPTABLE($parseString);
00164 break;
00165 case 'ALTERTABLE':
00166
00167 $result = $this->parseALTERTABLE($parseString);
00168 break;
00169 case 'CREATETABLE':
00170
00171 $result = $this->parseCREATETABLE($parseString);
00172 break;
00173 case 'CREATEDATABASE':
00174
00175 $result = $this->parseCREATEDATABASE($parseString);
00176 break;
00177 default:
00178 return $this->parseError('"'.$keyword.'" is not a keyword',$parseString);
00179 break;
00180 }
00181
00182 return $result;
00183 }
00184
00192 function parseSELECT($parseString) {
00193
00194 // Removing SELECT:
00195 $parseString = $this->trimSQL($parseString);
00196 $parseString = ltrim(substr($parseString,6)); // REMOVE eregi_replace('^SELECT[[:space:]]+','',$parseString);
00197
00198 // Init output variable:
00199 $result = array();
00200 $result['type'] = 'SELECT';
00201
00202 // Looking for STRAIGHT_JOIN keyword:
00203 $result['STRAIGHT_JOIN'] = $this->nextPart($parseString, '^(STRAIGHT_JOIN)[[:space:]]+');
00204
00205 // Select fields:
00206 $result['SELECT'] = $this->parseFieldList($parseString, '^(FROM)[[:space:]]+');
00207 if ($this->parse_error) { return $this->parse_error; }
00208
00209 // Continue if string is not ended:
00210 if ($parseString) {
00211
00212 // Get table list:
00213 $result['FROM'] = $this->parseFromTables($parseString, '^(WHERE)[[:space:]]+');
00214 if ($this->parse_error) { return $this->parse_error; }
00215
00216 // If there are more than just the tables (a WHERE clause that would be...)
00217 if ($parseString) {
00218
00219 // Get WHERE clause:
00220 $result['WHERE'] = $this->parseWhereClause($parseString, '^(GROUP[[:space:]]+BY|ORDER[[:space:]]+BY|LIMIT)[[:space:]]+');
00221 if ($this->parse_error) { return $this->parse_error; }
00222
00223 // If the WHERE clause parsing was stopped by GROUP BY, ORDER BY or LIMIT, then proceed with parsing:
00224 if ($this->lastStopKeyWord) {
00225
00226 // GROUP BY parsing:
00227 if ($this->lastStopKeyWord == 'GROUPBY') {
00228 $result['GROUPBY'] = $this->parseFieldList($parseString, '^(ORDER[[:space:]]+BY|LIMIT)[[:space:]]+');
00229 if ($this->parse_error) { return $this->parse_error; }
00230 }
00231
00232 // ORDER BY parsing:
00233 if ($this->lastStopKeyWord == 'ORDERBY') {
00234 $result['ORDERBY'] = $this->parseFieldList($parseString, '^(LIMIT)[[:space:]]+');
00235 if ($this->parse_error) { return $this->parse_error; }
00236 }
00237
00238 // LIMIT parsing:
00239 if ($this->lastStopKeyWord == 'LIMIT') {
00240 if (preg_match('/^([0-9]+|[0-9]+[[:space:]]*,[[:space:]]*[0-9]+)$/',trim($parseString))) {
00241 $result['LIMIT'] = $parseString;
00242 } else {
00243 return $this->parseError('No value for limit!',$parseString);
00244 }
00245 }
00246 }
00247 }
00248 } else return $this->parseError('No table to select from!',$parseString);
00249
00250 // Return result:
00251 return $result;
00252 }
00253
00261 function parseUPDATE($parseString) {
00262
00263 // Removing UPDATE
00264 $parseString = $this->trimSQL($parseString);
00265 $parseString = ltrim(substr($parseString,6)); // REMOVE eregi_replace('^UPDATE[[:space:]]+','',$parseString);
00266
00267 // Init output variable:
00268 $result = array();
00269 $result['type'] = 'UPDATE';
00270
00271 // Get table:
00272 $result['TABLE'] = $this->nextPart($parseString, '^([[:alnum:]_]+)[[:space:]]+');
00273
00274 // Continue if string is not ended:
00275 if ($result['TABLE']) {
00276 if ($parseString && $this->nextPart($parseString, '^(SET)[[:space:]]+')) {
00277
00278 $comma = TRUE;
00279
00280 // Get field/value pairs:
00281 while($comma) {
00282 if ($fieldName = $this->nextPart($parseString,'^([[:alnum:]_]+)[[:space:]]*=')) {
00283 $this->nextPart($parseString,'^(=)'); // Strip of "=" sign.
00284 $value = $this->getValue($parseString);
00285 $result['FIELDS'][$fieldName] = $value;
00286 } else return $this->parseError('No fieldname found',$parseString);
00287
00288 $comma = $this->nextPart($parseString,'^(,)');
00289 }
00290
00291 // WHERE
00292 if ($this->nextPart($parseString,'^(WHERE)')) {
00293 $result['WHERE'] = $this->parseWhereClause($parseString);
00294 if ($this->parse_error) { return $this->parse_error; }
00295 }
00296 } else return $this->parseError('Query missing SET...',$parseString);
00297 } else return $this->parseError('No table found!',$parseString);
00298
00299 // Should be no more content now:
00300 if ($parseString) {
00301 return $this->parseError('Still content in clause after parsing!',$parseString);
00302 }
00303
00304 // Return result:
00305 return $result;
00306 }
00307
00315 function parseINSERT($parseString) {
00316
00317 // Removing INSERT
00318 $parseString = $this->trimSQL($parseString);
00319 $parseString = ltrim(substr(ltrim(substr($parseString,6)),4)); // REMOVE eregi_replace('^INSERT[[:space:]]+INTO[[:space:]]+','',$parseString);
00320
00321 // Init output variable:
00322 $result = array();
00323 $result['type'] = 'INSERT';
00324
00325 // Get table:
00326 $result['TABLE'] = $this->nextPart($parseString, '^([[:alnum:]_]+)([[:space:]]+|\()');
00327
00328 if ($result['TABLE']) {
00329
00330 if ($this->nextPart($parseString,'^(VALUES)[[:space:]]+')) { // In this case there are no field names mentioned in the SQL!
00331 // Get values/fieldnames (depending...)
00332 $result['VALUES_ONLY'] = $this->getValue($parseString,'IN');
00333 if ($this->parse_error) { return $this->parse_error; }
00334 } else { // There are apparently fieldnames listed:
00335 $fieldNames = $this->getValue($parseString,'_LIST');
00336 if ($this->parse_error) { return $this->parse_error; }
00337
00338 if ($this->nextPart($parseString,'^(VALUES)[[:space:]]+')) { // "VALUES" keyword binds the fieldnames to values:
00339
00340 $values = $this->getValue($parseString,'IN'); // Using the "getValue" function to get the field list...
00341 if ($this->parse_error) { return $this->parse_error; }
00342
00343 foreach($fieldNames as $k => $fN) {
00344 if (preg_match('/^[[:alnum:]_]+$/',$fN)) {
00345 if (isset($values[$k])) {
00346 if (!isset($result['FIELDS'][$fN])) {
00347 $result['FIELDS'][$fN] = $values[$k];
00348 } else return $this->parseError('Fieldname ("'.$fN.'") already found in list!',$parseString);
00349 } else return $this->parseError('No value set!',$parseString);
00350 } else return $this->parseError('Invalid fieldname ("'.$fN.'")',$parseString);
00351 }
00352 if (isset($values[$k+1])) {
00353 return $this->parseError('Too many values in list!',$parseString);
00354 }
00355 } else return $this->parseError('VALUES keyword expected',$parseString);
00356 }
00357 } else return $this->parseError('No table found!',$parseString);
00358
00359 // Should be no more content now:
00360 if ($parseString) {
00361 return $this->parseError('Still content after parsing!',$parseString);
00362 }
00363
00364 // Return result
00365 return $result;
00366 }
00367
00375 function parseDELETE($parseString) {
00376
00377 // Removing DELETE
00378 $parseString = $this->trimSQL($parseString);
00379 $parseString = ltrim(substr(ltrim(substr($parseString,6)),4)); // REMOVE eregi_replace('^DELETE[[:space:]]+FROM[[:space:]]+','',$parseString);
00380
00381 // Init output variable:
00382 $result = array();
00383 $result['type'] = 'DELETE';
00384
00385 // Get table:
00386 $result['TABLE'] = $this->nextPart($parseString, '^([[:alnum:]_]+)[[:space:]]+');
00387
00388 if ($result['TABLE']) {
00389
00390 // WHERE
00391 if ($this->nextPart($parseString,'^(WHERE)')) {
00392 $result['WHERE'] = $this->parseWhereClause($parseString);
00393 if ($this->parse_error) { return $this->parse_error; }
00394 }
00395 } else return $this->parseError('No table found!',$parseString);
00396
00397 // Should be no more content now:
00398 if ($parseString) {
00399 return $this->parseError('Still content in clause after parsing!',$parseString);
00400 }
00401
00402 // Return result:
00403 return $result;
00404 }
00405
00413 function parseEXPLAIN($parseString) {
00414
00415 // Removing EXPLAIN
00416 $parseString = $this->trimSQL($parseString);
00417 $parseString = ltrim(substr($parseString,6)); // REMOVE eregi_replace('^EXPLAIN[[:space:]]+','',$parseString);
00418
00419 // Init output variable:
00420 $result = $this->parseSELECT($parseString);
00421 if (is_array($result)) {
00422 $result['type'] = 'EXPLAIN';
00423 }
00424
00425 return $result;
00426 }
00427
00435 function parseCREATETABLE($parseString) {
00436
00437 // Removing CREATE TABLE
00438 $parseString = $this->trimSQL($parseString);
00439 $parseString = ltrim(substr(ltrim(substr($parseString,6)),5)); // REMOVE eregi_replace('^CREATE[[:space:]]+TABLE[[:space:]]+','',$parseString);
00440
00441 // Init output variable:
00442 $result = array();
00443 $result['type'] = 'CREATETABLE';
00444
00445 // Get table:
00446 $result['TABLE'] = $this->nextPart($parseString, '^([[:alnum:]_]+)[[:space:]]*\(',TRUE);
00447
00448 if ($result['TABLE']) {
00449
00450 // While the parseString is not yet empty:
00451 while(strlen($parseString)>0) {
00452 if ($key = $this->nextPart($parseString, '^(KEY|PRIMARY KEY)([[:space:]]+|\()')) { // Getting key
00453 $key = strtoupper(str_replace(array(' ',"\t","\r","\n"),'',$key));
00454
00455 switch($key) {
00456 case 'PRIMARYKEY':
00457 $result['KEYS'][$key] = $this->getValue($parseString,'_LIST');
00458 if ($this->parse_error) { return $this->parse_error; }
00459 break;
00460 case 'KEY':
00461 if ($keyName = $this->nextPart($parseString, '^([[:alnum:]_]+)([[:space:]]+|\()')) {
00462 $result['KEYS'][$keyName] = $this->getValue($parseString,'_LIST');
00463 if ($this->parse_error) { return $this->parse_error; }
00464 } else return $this->parseError('No keyname found',$parseString);
00465 break;
00466 }
00467 } elseif ($fieldName = $this->nextPart($parseString, '^([[:alnum:]_]+)[[:space:]]+')) { // Getting field:
00468 $result['FIELDS'][$fieldName]['definition'] = $this->parseFieldDef($parseString);
00469 if ($this->parse_error) { return $this->parse_error; }
00470 }
00471
00472 // Finding delimiter:
00473 $delim = $this->nextPart($parseString, '^(,|\))');
00474 if (!$delim) {
00475 return $this->parseError('No delimiter found',$parseString);
00476 } elseif ($delim==')') {
00477 break;
00478 }
00479 }
00480
00481 // Finding what is after the table definition - table type in MySQL
00482 if ($delim==')') {
00483 if ($this->nextPart($parseString, '^(TYPE[[:space:]]*=)')) {
00484 $result['tableType'] = $parseString;
00485 $parseString = '';
00486 }
00487 } else return $this->parseError('No fieldname found!',$parseString);
00488
00489 // Getting table type
00490 } else return $this->parseError('No table found!',$parseString);
00491
00492 // Should be no more content now:
00493 if ($parseString) {
00494 return $this->parseError('Still content in clause after parsing!',$parseString);
00495 }
00496
00497 return $result;
00498 }
00499
00507 function parseALTERTABLE($parseString) {
00508
00509 // Removing ALTER TABLE
00510 $parseString = $this->trimSQL($parseString);
00511 $parseString = ltrim(substr(ltrim(substr($parseString,5)),5)); // REMOVE eregi_replace('^ALTER[[:space:]]+TABLE[[:space:]]+','',$parseString);
00512
00513 // Init output variable:
00514 $result = array();
00515 $result['type'] = 'ALTERTABLE';
00516
00517 // Get table:
00518 $result['TABLE'] = $this->nextPart($parseString, '^([[:alnum:]_]+)[[:space:]]+');
00519
00520 if ($result['TABLE']) {
00521 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:]]+|\()')) {
00522 $actionKey = strtoupper(str_replace(array(' ',"\t","\r","\n"),'',$result['action']));
00523
00524 // Getting field:
00525 if (t3lib_div::inList('ADDPRIMARYKEY,DROPPRIMARYKEY',$actionKey) || $fieldKey = $this->nextPart($parseString, '^([[:alnum:]_]+)[[:space:]]+')) {
00526
00527 switch($actionKey) {
00528 case 'ADD':
00529 $result['FIELD'] = $fieldKey;
00530 $result['definition'] = $this->parseFieldDef($parseString);
00531 if ($this->parse_error) { return $this->parse_error; }
00532 break;
00533 case 'DROP':
00534 case 'RENAME':
00535 $result['FIELD'] = $fieldKey;
00536 break;
00537 case 'CHANGE':
00538 $result['FIELD'] = $fieldKey;
00539 if ($result['newField'] = $this->nextPart($parseString, '^([[:alnum:]_]+)[[:space:]]+')) {
00540 $result['definition'] = $this->parseFieldDef($parseString);
00541 if ($this->parse_error) { return $this->parse_error; }
00542 } else return $this->parseError('No NEW field name found',$parseString);
00543 break;
00544
00545 case 'ADDKEY':
00546 case 'ADDPRIMARYKEY':
00547 $result['KEY'] = $fieldKey;
00548 $result['fields'] = $this->getValue($parseString,'_LIST');
00549 if ($this->parse_error) { return $this->parse_error; }
00550 break;
00551 case 'DROPKEY':
00552 $result['KEY'] = $fieldKey;
00553 break;
00554 case 'DROPPRIMARYKEY':
00555 // ??? todo!
00556 break;
00557 }
00558 } else return $this->parseError('No field name found',$parseString);
00559 } else return $this->parseError('No action CHANGE, DROP or ADD found!',$parseString);
00560 } else return $this->parseError('No table found!',$parseString);
00561
00562 // Should be no more content now:
00563 if ($parseString) {
00564 return $this->parseError('Still content in clause after parsing!',$parseString);
00565 }
00566
00567 return $result;
00568 }
00569
00576 function parseDROPTABLE($parseString) {
00577
00578 // Removing DROP TABLE
00579 $parseString = $this->trimSQL($parseString);
00580 $parseString = ltrim(substr(ltrim(substr($parseString,4)),5)); // eregi_replace('^DROP[[:space:]]+TABLE[[:space:]]+','',$parseString);
00581
00582 // Init output variable:
00583 $result = array();
00584 $result['type'] = 'DROPTABLE';
00585
00586 // IF EXISTS
00587 $result['ifExists'] = $this->nextPart($parseString, '^(IF[[:space:]]+EXISTS[[:space:]]+)');
00588
00589 // Get table:
00590 $result['TABLE'] = $this->nextPart($parseString, '^([[:alnum:]_]+)[[:space:]]+');
00591
00592 if ($result['TABLE']) {
00593
00594 // Should be no more content now:
00595 if ($parseString) {
00596 return $this->parseError('Still content in clause after parsing!',$parseString);
00597 }
00598
00599 return $result;
00600 } else return $this->parseError('No table found!',$parseString);
00601 }
00602
00609 function parseCREATEDATABASE($parseString) {
00610
00611 // Removing CREATE DATABASE
00612 $parseString = $this->trimSQL($parseString);
00613 $parseString = ltrim(substr(ltrim(substr($parseString,6)),8)); // eregi_replace('^CREATE[[:space:]]+DATABASE[[:space:]]+','',$parseString);
00614
00615 // Init output variable:
00616 $result = array();
00617 $result['type'] = 'CREATEDATABASE';
00618
00619 // Get table:
00620 $result['DATABASE'] = $this->nextPart($parseString, '^([[:alnum:]_]+)[[:space:]]+');
00621
00622 if ($result['DATABASE']) {
00623
00624 // Should be no more content now:
00625 if ($parseString) {
00626 return $this->parseError('Still content in clause after parsing!',$parseString);
00627 }
00628
00629 return $result;
00630 } else return $this->parseError('No database found!',$parseString);
00631 }
00632
00633
00634
00635
00636
00637
00638
00639
00640
00641
00642
00643
00644
00645
00646
00647 /**************************************
00648 *
00649 * SQL Parsing, helper functions for parts of queries
00650 *
00651 **************************************/
00652
00663 function parseFieldList(&$parseString, $stopRegex='') {
00664
00665 // Prepare variables:
00666 $parseString = $this->trimSQL($parseString);
00667 $this->lastStopKeyWord = '';
00668 $this->parse_error = '';
00669
00670
00671 $stack = array(); // Contains the parsed content
00672 $pnt = 0; // Pointer to positions in $stack
00673 $level = 0; // Indicates the parenthesis level we are at.
00674 $loopExit = 0; // Recursivity brake.
00675
00676 // $parseString is continously shortend by the process and we keep parsing it till it is zero:
00677 while (strlen($parseString)) {
00678
00679 // Checking if we are inside / outside parenthesis (in case of a function like count(), max(), min() etc...):
00680 if ($level>0) { // Inside parenthesis here (does NOT detect if values in quotes are used, the only token is ")" or "("):
00681
00682 // Accumulate function content until next () parenthesis:
00683 $funcContent = $this->nextPart($parseString,'^([^()]*.)');
00684 $stack[$pnt]['func_content.'][] = array(
00685 'level' => $level,
00686 'func_content' => substr($funcContent,0,-1)
00687 );
00688 $stack[$pnt]['func_content'].= $funcContent;
00689
00690 // Detecting ( or )
00691 switch(substr($stack[$pnt]['func_content'],-1)) {
00692 case '(':
00693 $level++;
00694 break;
00695 case ')':
00696 $level--;
00697 if (!$level) { // If this was the last parenthesis:
00698 $stack[$pnt]['func_content'] = substr($stack[$pnt]['func_content'],0,-1);
00699 $parseString = ltrim($parseString); // Remove any whitespace after the parenthesis.
00700 }
00701 break;
00702 }
00703 } else { // Outside parenthesis, looking for next field:
00704
00705 // Looking for a known function (only known functions supported)
00706 $func = $this->nextPart($parseString,'^(count|max|min|floor|sum|avg)[[:space:]]*\(');
00707 if ($func) {
00708 $parseString = trim(substr($parseString,1)); // Strip of "("
00709 $stack[$pnt]['type'] = 'function';
00710 $stack[$pnt]['function'] = $func;
00711 $level++; // increse parenthesis level counter.
00712 } else {
00713 // Otherwise, look for regular fieldname:
00714 if ($fieldName = $this->nextPart($parseString,'^([[:alnum:]\*._]+)(,|[[:space:]]+)')) {
00715 $stack[$pnt]['type'] = 'field';
00716
00717 // Explode fieldname into field and table:
00718 $tableField = explode('.',$fieldName,2);
00719 if (count($tableField)==2) {
00720 $stack[$pnt]['table'] = $tableField[0];
00721 $stack[$pnt]['field'] = $tableField[1];
00722 } else {
00723 $stack[$pnt]['table'] = '';
00724 $stack[$pnt]['field'] = $tableField[0];
00725 }
00726 } else {
00727 return $this->parseError('No field name found as expected',$parseString);
00728 }
00729 }
00730 }
00731
00732 // After a function or field we look for "AS" alias and a comma to separate to the next field in the list:
00733 if (!$level) {
00734
00735 // Looking for "AS" alias:
00736 if ($as = $this->nextPart($parseString,'^(AS)[[:space:]]+')) {
00737 $stack[$pnt]['as'] = $this->nextPart($parseString,'^([[:alnum:]_]+)(,|[[:space:]]+)');
00738 $stack[$pnt]['as_keyword'] = $as;
00739 }
00740
00741 // Looking for "ASC" or "DESC" keywords (for ORDER BY)
00742 if ($sDir = $this->nextPart($parseString,'^(ASC|DESC)([[:space:]]+|,)')) {
00743 $stack[$pnt]['sortDir'] = $sDir;
00744 }
00745
00746 // Looking for stop-keywords:
00747 if ($stopRegex && $this->lastStopKeyWord = $this->nextPart($parseString, $stopRegex)) {
00748 $this->lastStopKeyWord = strtoupper(str_replace(array(' ',"\t","\r","\n"),'',$this->lastStopKeyWord));
00749 return $stack;
00750 }
00751
00752 // Looking for comma (since the stop-keyword did not trigger a return...)
00753 if (strlen($parseString) && !$this->nextPart($parseString,'^(,)')) {
00754 return $this->parseError('No comma found as expected',$parseString);
00755 }
00756
00757 // Increasing pointer:
00758 $pnt++;
00759 }
00760
00761 // Check recursivity brake:
00762 $loopExit++;
00763 if ($loopExit>500) {
00764 return $this->parseError('More than 500 loops, exiting prematurely...',$parseString);
00765 }
00766 }
00767
00768 // Return result array:
00769 return $stack;
00770 }
00771
00781 function parseFromTables(&$parseString, $stopRegex='') {
00782
00783 // Prepare variables:
00784 $parseString = $this->trimSQL($parseString);
00785 $this->lastStopKeyWord = '';
00786 $this->parse_error = '';
00787
00788 $stack = array(); // Contains the parsed content
00789 $pnt = 0; // Pointer to positions in $stack
00790 $loopExit = 0; // Recursivity brake.
00791
00792 // $parseString is continously shortend by the process and we keep parsing it till it is zero:
00793 while (strlen($parseString)) {
00794 // Looking for the table:
00795 if ($stack[$pnt]['table'] = $this->nextPart($parseString,'^([[:alnum:]_]+)(,|[[:space:]]+)')) {
00796 $stack[$pnt]['as'] = $this->nextPart($parseString,'^([[:alnum:]_]+)[[:space:]]*');
00797 } else return $this->parseError('No table name found as expected!',$parseString);
00798
00799 // Looking for JOIN
00800 if ($join = $this->nextPart($parseString,'^(JOIN|LEFT[[:space:]]+JOIN)[[:space:]]+')) {
00801 $stack[$pnt]['JOIN']['type'] = $join;
00802 if ($stack[$pnt]['JOIN']['withTable'] = $this->nextPart($parseString,'^([[:alnum:]_]+)[[:space:]]+ON[[:space:]]+',1)) {
00803 $field1 = $this->nextPart($parseString,'^([[:alnum:]_.]+)[[:space:]]*=[[:space:]]*',1);
00804 $field2 = $this->nextPart($parseString,'^([[:alnum:]_.]+)[[:space:]]+');
00805 if ($field1 && $field2) {
00806 $stack[$pnt]['JOIN']['ON'] = array($field1,$field2);
00807 } else return $this->parseError('No join fields found!',$parseString);
00808 } else return $this->parseError('No join table found!',$parseString);
00809 }
00810
00811 // Looking for stop-keywords:
00812 if ($stopRegex && $this->lastStopKeyWord = $this->nextPart($parseString, $stopRegex)) {
00813 $this->lastStopKeyWord = strtoupper(str_replace(array(' ',"\t","\r","\n"),'',$this->lastStopKeyWord));
00814 return $stack;
00815 }
00816
00817 // Looking for comma:
00818 if (strlen($parseString) && !$this->nextPart($parseString,'^(,)')) {
00819 return $this->parseError('No comma found as expected',$parseString);
00820 }
00821
00822 // Increasing pointer:
00823 $pnt++;
00824
00825 // Check recursivity brake:
00826 $loopExit++;
00827 if ($loopExit>500) {
00828 return $this->parseError('More than 500 loops, exiting prematurely...',$parseString);
00829 }
00830 }
00831
00832 // Return result array:
00833 return $stack;
00834 }
00835
00844 function parseWhereClause(&$parseString, $stopRegex='') {
00845
00846 // Prepare variables:
00847 $parseString = $this->trimSQL($parseString);
00848 $this->lastStopKeyWord = '';
00849 $this->parse_error = '';
00850
00851 $stack = array(0 => array()); // Contains the parsed content
00852 $pnt = array(0 => 0); // Pointer to positions in $stack
00853 $level = 0; // Determines parenthesis level
00854 $loopExit = 0; // Recursivity brake.
00855
00856 // $parseString is continously shortend by the process and we keep parsing it till it is zero:
00857 while (strlen($parseString)) {
00858
00859 // Look for next parenthesis level:
00860 $newLevel = $this->nextPart($parseString,'^([(])');
00861 if ($newLevel=='(') { // If new level is started, manage stack/pointers:
00862 $level++; // Increase level
00863 $pnt[$level] = 0; // Reset pointer for this level
00864 $stack[$level] = array(); // Reset stack for this level
00865 } else { // If no new level is started, just parse the current level:
00866
00867 // Find "modifyer", eg. "NOT or !"
00868 $stack[$level][$pnt[$level]]['modifier'] = trim($this->nextPart($parseString,'^(!|NOT[[:space:]]+)'));
00869
00870 // Fieldname:
00871 if ($fieldName = $this->nextPart($parseString,'^([[:alnum:]._]+)([[:space:]]+|&|<=|>=|<|>|=|!=|IS)')) {
00872
00873 // Parse field name into field and table:
00874 $tableField = explode('.',$fieldName,2);
00875 if (count($tableField)==2) {
00876 $stack[$level][$pnt[$level]]['table'] = $tableField[0];
00877 $stack[$level][$pnt[$level]]['field'] = $tableField[1];
00878 } else {
00879 $stack[$level][$pnt[$level]]['table'] = '';
00880 $stack[$level][$pnt[$level]]['field'] = $tableField[0];
00881 }
00882 } else {
00883 return $this->parseError('No field name found as expected',$parseString);
00884 }
00885
00886 // See if the value is calculated. Support only for "&" (boolean AND) at the moment:
00887 $stack[$level][$pnt[$level]]['calc'] = $this->nextPart($parseString,'^(&)');
00888 if (strlen($stack[$level][$pnt[$level]]['calc'])) {
00889 // Finding value for calculation:
00890 $stack[$level][$pnt[$level]]['calc_value'] = $this->getValue($parseString);
00891 }
00892
00893 // Find "comparator":
00894 $stack[$level][$pnt[$level]]['comparator'] = $this->nextPart($parseString,'^(<=|>=|<|>|=|!=|NOT[[:space:]]+IN|IN|NOT[[:space:]]+LIKE|LIKE|IS)');
00895 if (strlen($stack[$level][$pnt[$level]]['comparator'])) {
00896 // Finding value for comparator:
00897 $stack[$level][$pnt[$level]]['value'] = $this->getValue($parseString,$stack[$level][$pnt[$level]]['comparator']);
00898 if ($this->parse_error) { return $this->parse_error; }
00899 }
00900
00901 // Finished, increase pointer:
00902 $pnt[$level]++;
00903
00904 // Checking if the current level is ended, in that case do stack management:
00905 while ($this->nextPart($parseString,'^([)])')) {
00906 $level--; // Decrease level:
00907 $stack[$level][$pnt[$level]]['sub'] = $stack[$level+1]; // Copy stack
00908 $pnt[$level]++; // Increase pointer of the new level
00909
00910 // Make recursivity check:
00911 $loopExit++;
00912 if ($loopExit>500) {
00913 return $this->parseError('More than 500 loops (in search for exit parenthesis), exiting prematurely...',$parseString);
00914 }
00915 }
00916
00917 // Detecting the operator for the next level; support for AND, OR and &&):
00918 $op = $this->nextPart($parseString,'^(AND|OR|AND[[:space:]]+NOT)(\(|[[:space:]]+)');
00919 if ($op) {
00920 $stack[$level][$pnt[$level]]['operator'] = $op;
00921 } elseif (strlen($parseString)) {
00922
00923 // Looking for stop-keywords:
00924 if ($stopRegex && $this->lastStopKeyWord = $this->nextPart($parseString, $stopRegex)) {
00925 $this->lastStopKeyWord = strtoupper(str_replace(array(' ',"\t","\r","\n"),'',$this->lastStopKeyWord));
00926 return $stack[0];
00927 } else {
00928 return $this->parseError('No operator, but parsing not finished.',$parseString);
00929 }
00930 }
00931 }
00932
00933 // Make recursivity check:
00934 $loopExit++;
00935 if ($loopExit>500) {
00936 return $this->parseError('More than 500 loops, exiting prematurely...',$parseString);
00937 }
00938 }
00939
00940 // Return the stacks lowest level:
00941 return $stack[0];
00942 }
00943
00952 function parseFieldDef(&$parseString, $stopRegex='') {
00953 // Prepare variables:
00954 $parseString = $this->trimSQL($parseString);
00955 $this->lastStopKeyWord = '';
00956 $this->parse_error = '';
00957
00958 $result = array();
00959
00960 // Field type:
00961 if ($result['fieldType'] = $this->nextPart($parseString,'^(int|smallint|tinyint|mediumint|bigint|double|numeric|decimal|varchar|char|text|tinytext|mediumtext|longtext|blob|tinyblob|mediumblob|longblob)([[:space:]]+|\()')) {
00962
00963 // Looking for value:
00964 if (substr($parseString,0,1)=='(') {
00965 $parseString = substr($parseString,1);
00966 if ($result['value'] = $this->nextPart($parseString,'^([^)]*)')) {
00967 $parseString = ltrim(substr($parseString,1));
00968 } else return $this->parseError('No end-parenthesis for value found!',$parseString);
00969 }
00970
00971 // Looking for keywords
00972 while($keyword = $this->nextPart($parseString,'^(DEFAULT|NOT[[:space:]]+NULL|AUTO_INCREMENT|UNSIGNED)([[:space:]]+|,|\))')) {
00973 $keywordCmp = strtoupper(str_replace(array(' ',"\t","\r","\n"),'',$keyword));
00974
00975 $result['featureIndex'][$keywordCmp]['keyword'] = $keyword;
00976
00977 switch($keywordCmp) {
00978 case 'DEFAULT':
00979 $result['featureIndex'][$keywordCmp]['value'] = $this->getValue($parseString);
00980 break;
00981 }
00982 }
00983 } else return $this->parseError('Field type unknown!',$parseString);
00984
00985 return $result;
00986 }
00987
00988
00989
00990
00991
00992
00993
00994
00995
00996
00997
00998 /************************************
00999 *
01000 * Parsing: Helper functions
01001 *
01002 ************************************/
01003
01013 function nextPart(&$parseString,$regex,$trimAll=FALSE) {
01014 //if (eregi($regex,$parseString.' ', $reg)) { // Adding space char because [[:space:]]+ is often a requirement in regex's
01015 if (preg_match('/'.$regex.'/i',$parseString.' ', $reg)) { // Adding space char because [[:space:]]+ is often a requirement in regex's
01016 $parseString = ltrim(substr($parseString,strlen($reg[$trimAll?0:1])));
01017 return $reg[1];
01018 }
01019 }
01020
01028 function getValue(&$parseString,$comparator='') {
01029 //if (t3lib_div::inList('NOTIN,IN,_LIST',strtoupper(ereg_replace('[[:space:]]','',$comparator)))) { // List of values:
01030 if (t3lib_div::inList('NOTIN,IN,_LIST',strtoupper(str_replace(array(' ',"\n","\r","\t"),'',$comparator)))) { // List of values:
01031 if ($this->nextPart($parseString,'^([(])')) {
01032 $listValues = array();
01033 $comma=',';
01034
01035 while($comma==',') {
01036 $listValues[] = $this->getValue($parseString);
01037 $comma = $this->nextPart($parseString,'^([,])');
01038 }
01039
01040 $out = $this->nextPart($parseString,'^([)])');
01041 if ($out) {
01042 if ($comparator=='_LIST') {
01043 $kVals = array();
01044 foreach ($listValues as $vArr) {
01045 $kVals[] = $vArr[0];
01046 }
01047 return $kVals;
01048 } else {
01049 return $listValues;
01050 }
01051 } else return array($this->parseError('No ) parenthesis in list',$parseString));
01052 } else return array($this->parseError('No ( parenthesis starting the list',$parseString));
01053
01054 } else { // Just plain string value, in quotes or not:
01055
01056 // Quote?
01057 $firstChar = substr($parseString,0,1);
01058
01059 switch($firstChar) {
01060 case '"':
01061 return array($this->getValueInQuotes($parseString,'"'),'"');
01062 break;
01063 case "'":
01064 return array($this->getValueInQuotes($parseString,"'"),"'");
01065 break;
01066 default:
01067 if (preg_match('/^([[:alnum:]._-]+)/i',$parseString, $reg)) {
01068 $parseString = ltrim(substr($parseString,strlen($reg[0])));
01069 return array($reg[1]);
01070 }
01071 break;
01072 }
01073 }
01074 }
01075
01084 function getValueInQuotes(&$parseString,$quote) {
01085
01086 $parts = explode($quote,substr($parseString,1));
01087 $buffer = '';
01088 foreach($parts as $k => $v) {
01089 $buffer.=$v;
01090
01091 unset($reg);
01092
01093 ereg('[\]*$',$v,$reg);
01094 if (strlen($reg[0])%2) {
01095 $buffer.=$quote;
01096 } else {
01097 $parseString = ltrim(substr($parseString,strlen($buffer)+2));
01098 return $this->parseStripslashes($buffer);
01099 }
01100 }
01101 }
01102
01110 function parseStripslashes($str) {
01111 $search = array('\\\\', '\\\'', '\\"', '\0', '\n', '\r', '\Z');
01112 $replace = array('\\', '\'', '"', "\x00", "\x0a", "\x0d", "\x1a");
01113
01114 return str_replace($search, $replace, $str);
01115 }
01116
01124 function compileAddslashes($str) {
01125 return $str;
01126 $search = array('\\', '\'', '"', "\x00", "\x0a", "\x0d", "\x1a");
01127 $replace = array('\\\\', '\\\'', '\\"', '\0', '\n', '\r', '\Z');
01128
01129 return str_replace($search, $replace, $str);
01130 }
01131
01139 function parseError($msg,$restQuery) {
01140 $this->parse_error = 'SQL engine parse ERROR: '.$msg.': near "'.substr($restQuery,0,50).'"';
01141 return $this->parse_error;
01142 }
01143
01153 function trimSQL($str) {
01154 return trim(rtrim($str, "; \r\n\t")).' ';
01155
01156 }
01157
01158
01159
01160
01161
01162
01163
01164
01165
01166
01167
01168
01169
01170
01171
01172
01173
01174
01182 function compileSQL($components) {
01183 switch($components['type']) {
01184 case 'SELECT':
01185 $query = $this->compileSELECT($components);
01186 break;
01187 case 'UPDATE':
01188 $query = $this->compileUPDATE($components);
01189 break;
01190 case 'INSERT':
01191 $query = $this->compileINSERT($components);
01192 break;
01193 case 'DELETE':
01194 $query = $this->compileDELETE($components);
01195 break;
01196 case 'EXPLAIN':
01197 $query = 'EXPLAIN '.$this->compileSELECT($components);
01198 break;
01199 case 'DROPTABLE':
01200 $query = 'DROP TABLE'.($components['ifExists']?' IF EXISTS':'').' '.$components['TABLE'];
01201 break;
01202 case 'CREATETABLE':
01203 $query = $this->compileCREATETABLE($components);
01204 break;
01205 case 'ALTERTABLE':
01206 $query = $this->compileALTERTABLE($components);
01207 break;
01208 }
01209
01210 return $query;
01211 }
01212
01220 function compileSELECT($components) {
01221
01222
01223 $where = $this->compileWhereClause($components['WHERE']);
01224 $groupBy = $this->compileFieldList($components['GROUPBY']);
01225 $orderBy = $this->compileFieldList($components['ORDERBY']);
01226 $limit = $components['LIMIT'];
01227
01228
01229 $query = 'SELECT '.($components['STRAIGHT_JOIN'] ? $components['STRAIGHT_JOIN'].'' : '').'
01230 '.$this->compileFieldList($components['SELECT']).'
01231 FROM '.$this->compileFromTables($components['FROM']).
01232 (strlen($where)?'
01233 WHERE '.$where : '').
01234 (strlen($groupBy)?'
01235 GROUP BY '.$groupBy : '').
01236 (strlen($orderBy)?'
01237 ORDER BY '.$orderBy : '').
01238 (strlen($limit)?'
01239 LIMIT '.$limit : '');
01240
01241 return $query;
01242 }
01243
01251 function compileUPDATE($components) {
01252
01253
01254 $where = $this->compileWhereClause($components['WHERE']);
01255
01256
01257 $fields = array();
01258 foreach($components['FIELDS'] as $fN => $fV) {
01259 $fields[]=$fN.'='.$fV[1].$this->compileAddslashes($fV[0]).$fV[1];
01260 }
01261
01262
01263 $query = 'UPDATE '.$components['TABLE'].' SET
01264 '.implode(',
01265 ',$fields).'
01266 '.(strlen($where)?'
01267 WHERE '.$where : '');
01268
01269 return $query;
01270 }
01271
01279 function compileINSERT($components) {
01280
01281 if ($components['VALUES_ONLY']) {
01282
01283 $fields = array();
01284 foreach($components['VALUES_ONLY'] as $fV) {
01285 $fields[]=$fV[1].$this->compileAddslashes($fV[0]).$fV[1];
01286 }
01287
01288
01289 $query = 'INSERT INTO '.$components['TABLE'].'
01290 VALUES
01291 ('.implode(',
01292 ',$fields).')';
01293 } else {
01294
01295 $fields = array();
01296 foreach($components['FIELDS'] as $fN => $fV) {
01297 $fields[$fN]=$fV[1].$this->compileAddslashes($fV[0]).$fV[1];
01298 }
01299
01300
01301 $query = 'INSERT INTO '.$components['TABLE'].'
01302 ('.implode(',
01303 ',array_keys($fields)).')
01304 VALUES
01305 ('.implode(',
01306 ',$fields).')';
01307 }
01308
01309 return $query;
01310 }
01311
01319 function compileDELETE($components) {
01320
01321
01322 $where = $this->compileWhereClause($components['WHERE']);
01323
01324
01325 $query = 'DELETE FROM '.$components['TABLE'].
01326 (strlen($where)?'
01327 WHERE '.$where : '');
01328
01329 return $query;
01330 }
01331
01339 function compileCREATETABLE($components) {
01340
01341
01342 $fieldsKeys = array();
01343 foreach($components['FIELDS'] as $fN => $fCfg) {
01344 $fieldsKeys[]=$fN.' '.$this->compileFieldCfg($fCfg['definition']);
01345 }
01346 foreach($components['KEYS'] as $kN => $kCfg) {
01347 if ($kN == 'PRIMARYKEY') {
01348 $fieldsKeys[]='PRIMARY KEY ('.implode(',', $kCfg).')';
01349 } else {
01350 $fieldsKeys[]='KEY '.$kN.' ('.implode(',', $kCfg).')';
01351 }
01352 }
01353
01354
01355 $query = 'CREATE TABLE '.$components['TABLE'].' (
01356 '.implode(',
01357 ', $fieldsKeys).'
01358 )'.($components['tableType'] ? ' TYPE='.$components['tableType'] : '');
01359
01360 return $query;
01361 }
01362
01370 function compileALTERTABLE($components) {
01371
01372
01373 $query = 'ALTER TABLE '.$components['TABLE'].' '.$components['action'].' '.($components['FIELD']?$components['FIELD']:$components['KEY']);
01374
01375
01376 switch(strtoupper(str_replace(array(' ',"\t","\r","\n"),'',$components['action']))) {
01377 case 'ADD':
01378 $query.=' '.$this->compileFieldCfg($components['definition']);
01379 break;
01380 case 'CHANGE':
01381 $query.=' '.$components['newField'].' '.$this->compileFieldCfg($components['definition']);
01382 break;
01383 case 'DROP':
01384 case 'DROPKEY':
01385 break;
01386 case 'ADDKEY':
01387 case 'ADDPRIMARYKEY':
01388 $query.=' ('.implode(',',$components['fields']).')';
01389 break;
01390 }
01391
01392
01393 return $query;
01394 }
01395
01396
01397
01398
01399
01400
01401
01402
01403
01404
01405
01406
01407
01408
01409
01410
01411
01412
01413
01414
01423 function compileFieldList($selectFields) {
01424
01425
01426 $outputParts = array();
01427
01428
01429 if (is_array($selectFields)) {
01430 foreach($selectFields as $k => $v) {
01431
01432
01433 switch($v['type']) {
01434 case 'function':
01435 $outputParts[$k] = $v['function'].'('.$v['func_content'].')';
01436 break;
01437 case 'field':
01438 $outputParts[$k] = ($v['table']?$v['table'].'.':'').$v['field'];
01439 break;
01440 }
01441
01442
01443 if ($v['as']) {
01444 $outputParts[$k].= ' '.$v['as_keyword'].' '.$v['as'];
01445 }
01446
01447
01448 if ($v['sortDir']) {
01449 $outputParts[$k].= ' '.$v['sortDir'];
01450 }
01451 }
01452 }
01453
01454
01455 return implode(', ',$outputParts);
01456 }
01457
01465 function compileFromTables($tablesArray) {
01466
01467
01468 $outputParts = array();
01469
01470
01471 if (is_array($tablesArray)) {
01472 foreach($tablesArray as $k => $v) {
01473
01474
01475 $outputParts[$k] = $v['table'];
01476
01477
01478 if ($v['as']) {
01479 $outputParts[$k].= ' '.$v['as_keyword'].' '.$v['as'];
01480 }
01481
01482 if (is_array($v['JOIN'])) {
01483 $outputParts[$k].= ' '.$v['JOIN']['type'].' '.$v['JOIN']['withTable'].' ON '.implode('=',$v['JOIN']['ON']);
01484 }
01485
01486 }
01487 }
01488
01489
01490 return implode(', ',$outputParts);
01491 }
01492
01502 function compileWhereClause($clauseArray) {
01503
01504
01505 $output='';
01506
01507
01508 if (is_array($clauseArray)) {
01509 foreach($clauseArray as $k => $v) {
01510
01511
01512 $output.=$v['operator'] ? ' '.$v['operator'] : '';
01513
01514
01515 if (is_array($v['sub'])) {
01516 $output.=' ('.trim($this->compileWhereClause($v['sub'])).')';
01517 } else {
01518
01519
01520 $output.=' '.trim($v['modifier'].' '.($v['table']?$v['table'].'.':'').$v['field']);
01521
01522
01523 if ($v['calc']) {
01524 $output.=$v['calc'].$v['calc_value'][1].$this->compileAddslashes($v['calc_value'][0]).$v['calc_value'][1];
01525 }
01526
01527
01528 if ($v['comparator']) {
01529 $output.=' '.$v['comparator'];
01530
01531
01532 if (t3lib_div::inList('NOTIN,IN',strtoupper(str_replace(array(' ',"\t","\r","\n"),'',$v['comparator'])))) {
01533 $valueBuffer = array();
01534 foreach($v['value'] as $realValue) {
01535 $valueBuffer[]=$realValue[1].$this->compileAddslashes($realValue[0]).$realValue[1];
01536 }
01537 $output.=' ('.trim(implode(',',$valueBuffer)).')';
01538 } else {
01539 $output.=' '.$v['value'][1].$this->compileAddslashes($v['value'][0]).$v['value'][1];
01540 }
01541 }
01542 }
01543 }
01544 }
01545
01546
01547 return $output;
01548 }
01549
01556 function compileFieldCfg($fieldCfg) {
01557
01558
01559 $cfg = $fieldCfg['fieldType'];
01560
01561
01562 if (strlen($fieldCfg['value'])) {
01563 $cfg.='('.$fieldCfg['value'].')';
01564 }
01565
01566
01567 if (is_array($fieldCfg['featureIndex'])) {
01568 foreach($fieldCfg['featureIndex'] as $featureDef) {
01569 $cfg.=' '.$featureDef['keyword'];
01570
01571
01572 if (is_array($featureDef['value'])) {
01573 $cfg.=' '.$featureDef['value'][1].$this->compileAddslashes($featureDef['value'][0]).$featureDef['value'][1];
01574 }
01575 }
01576 }
01577
01578
01579 return $cfg;
01580 }
01581
01582
01583
01584
01585
01586
01587
01588
01589
01590
01591
01592
01593
01594
01595
01596
01597
01605 function debug_parseSQLpart($part,$str) {
01606 switch($part) {
01607 case 'SELECT':
01608 return $this->debug_parseSQLpartCompare($str,$this->compileFieldList($this->parseFieldList($str)));
01609 break;
01610 case 'FROM':
01611 return $this->debug_parseSQLpartCompare($str,$this->compileFromTables($this->parseFromTables($str)));
01612 break;
01613 case 'WHERE':
01614 return $this->debug_parseSQLpartCompare($str,$this->compileWhereClause($this->parseWhereClause($str)));
01615 break;
01616 }
01617 }
01618
01627 function debug_parseSQLpartCompare($str,$newStr,$caseInsensitive=FALSE) {
01628 if ($caseInsensitive) {
01629 $str1 = strtoupper($str);
01630 $str2 = strtoupper($newStr);
01631 } else {
01632 $str1 = $str;
01633 $str2 = $newStr;
01634 }
01635
01636
01637 $search = array('\0', '\n', '\r', '\Z');
01638 $replace = array("\x00", "\x0a", "\x0d", "\x1a");
01639 $str1 = str_replace($search, $replace, $str1);
01640 $str2 = str_replace($search, $replace, $str2);
01641
01642 # Normally, commented out since they are needed only in tricky cases...
01643 # $str1 = stripslashes($str1);
01644 # $str2 = stripslashes($str2);
01645
01646 if (strcmp(str_replace(array(' ',"\t","\r","\n"),'',$this->trimSQL($str1)),str_replace(array(' ',"\t","\r","\n"),'',$this->trimSQL($str2)))) {
01647 return array(
01648 str_replace(array(' ',"\t","\r","\n"),' ',$str),
01649 str_replace(array(' ',"\t","\r","\n"),' ',$newStr),
01650 );
01651 }
01652 }
01653
01660 function debug_testSQL($SQLquery) {
01661 # return $SQLquery;
01662 #debug(array($SQLquery));
01663
01664
01665 $parseResult = $this->parseSQL($SQLquery);
01666
01667
01668 if (is_array($parseResult)) {
01669
01670
01671 $newQuery = $this->compileSQL($parseResult);
01672
01673
01674 $testResult = $this->debug_parseSQLpartCompare($SQLquery, $newQuery);
01675
01676
01677 if (!is_array($testResult)) {
01678 return $newQuery;
01679 } else {
01680 debug(array('ERROR MESSAGE'=>'Input query did not match the parsed and recompiled query exactly (not observing whitespace)', 'TEST result' => $testResult),'SQL parsing failed:');
01681 exit;
01682 }
01683 } else {
01684 debug(array('query' => $SQLquery, 'ERROR MESSAGE'=>$parseResult),'SQL parsing failed:');
01685 exit;
01686 }
01687 }
01688 }
01689
01690
01691 if (defined('TYPO3_MODE') && $TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['t3lib/class.t3lib_sqlparser.php']) {
01692 include_once($TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['t3lib/class.t3lib_sqlparser.php']);
01693 }
01694 ?>