Bug #22410 » 14050_cleaning_t3lib_sqlparser.patch
t3lib/class.t3lib_sqlparser.php (revision ) | ||
---|---|---|
<?php
|
||
/***************************************************************
|
||
* Copyright notice
|
||
*
|
||
* (c) 2004-2010 Kasper Sk?rh?j (kasperYYYY@typo3.com)
|
||
* All rights reserved
|
||
*
|
||
* This script is part of the TYPO3 project. The TYPO3 project is
|
||
* free software; you can redistribute it and/or modify
|
||
* it under the terms of the GNU General Public License as published by
|
||
* the Free Software Foundation; either version 2 of the License, or
|
||
* (at your option) any later version.
|
||
*
|
||
* The GNU General Public License can be found at
|
||
* http://www.gnu.org/copyleft/gpl.html.
|
||
* A copy is found in the textfile GPL.txt and important notices to the license
|
||
* from the author is found in LICENSE.txt distributed with these scripts.
|
||
*
|
||
*
|
||
* This script is distributed in the hope that it will be useful,
|
||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
* GNU General Public License for more details.
|
||
*
|
||
* This copyright notice MUST APPEAR in all copies of the script!
|
||
***************************************************************/
|
||
* Copyright notice
|
||
*
|
||
* (c) 2004-2010 Kasper Sk?rh?j (kasperYYYY@typo3.com)
|
||
* All rights reserved
|
||
*
|
||
* This script is part of the TYPO3 project. The TYPO3 project is
|
||
* free software; you can redistribute it and/or modify
|
||
* it under the terms of the GNU General Public License as published by
|
||
* the Free Software Foundation; either version 2 of the License, or
|
||
* (at your option) any later version.
|
||
*
|
||
* The GNU General Public License can be found at
|
||
* http://www.gnu.org/copyleft/gpl.html.
|
||
* A copy is found in the textfile GPL.txt and important notices to the license
|
||
* from the author is found in LICENSE.txt distributed with these scripts.
|
||
*
|
||
*
|
||
* This script is distributed in the hope that it will be useful,
|
||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
* GNU General Public License for more details.
|
||
*
|
||
* This copyright notice MUST APPEAR in all copies of the script!
|
||
***************************************************************/
|
||
/**
|
||
* TYPO3 SQL parser
|
||
*
|
||
... | ... | |
*
|
||
* 107: class t3lib_sqlparser
|
||
*
|
||
* SECTION: SQL Parsing, full queries
|
||
* SECTION: SQL Parsing, full queries
|
||
* 129: function parseSQL($parseString)
|
||
* 129: function parseSQL($parseString)
|
||
* 192: function parseSELECT($parseString)
|
||
* 192: function parseSELECT($parseString)
|
||
* 261: function parseUPDATE($parseString)
|
||
* 261: function parseUPDATE($parseString)
|
||
* 315: function parseINSERT($parseString)
|
||
* 315: function parseINSERT($parseString)
|
||
* 375: function parseDELETE($parseString)
|
||
* 375: function parseDELETE($parseString)
|
||
* 413: function parseEXPLAIN($parseString)
|
||
* 413: function parseEXPLAIN($parseString)
|
||
* 435: function parseCREATETABLE($parseString)
|
||
* 435: function parseCREATETABLE($parseString)
|
||
* 514: function parseALTERTABLE($parseString)
|
||
* 514: function parseALTERTABLE($parseString)
|
||
* 583: function parseDROPTABLE($parseString)
|
||
* 583: function parseDROPTABLE($parseString)
|
||
* 616: function parseCREATEDATABASE($parseString)
|
||
* 616: function parseCREATEDATABASE($parseString)
|
||
*
|
||
* SECTION: SQL Parsing, helper functions for parts of queries
|
||
* SECTION: SQL Parsing, helper functions for parts of queries
|
||
* 670: function parseFieldList(&$parseString, $stopRegex='')
|
||
* 670: function parseFieldList(&$parseString, $stopRegex='')
|
||
* 791: function parseFromTables(&$parseString, $stopRegex='')
|
||
* 791: function parseFromTables(&$parseString, $stopRegex='')
|
||
* 882: function parseWhereClause(&$parseString, $stopRegex='')
|
||
* 882: function parseWhereClause(&$parseString, $stopRegex='')
|
||
* 990: function parseFieldDef(&$parseString, $stopRegex='')
|
||
* 990: function parseFieldDef(&$parseString, $stopRegex='')
|
||
*
|
||
* SECTION: Parsing: Helper functions
|
||
* SECTION: Parsing: Helper functions
|
||
* 1053: function nextPart(&$parseString,$regex,$trimAll=FALSE)
|
||
* 1053: function nextPart(&$parseString,$regex,$trimAll=FALSE)
|
||
* 1068: function getValue(&$parseString,$comparator='')
|
||
* 1068: function getValue(&$parseString,$comparator='')
|
||
* 1127: function getValueInQuotes(&$parseString,$quote)
|
||
* 1127: function getValueInQuotes(&$parseString,$quote)
|
||
* 1153: function parseStripslashes($str)
|
||
* 1153: function parseStripslashes($str)
|
||
* 1167: function compileAddslashes($str)
|
||
* 1167: function compileAddslashes($str)
|
||
* 1182: function parseError($msg,$restQuery)
|
||
* 1182: function parseError($msg,$restQuery)
|
||
* 1196: function trimSQL($str)
|
||
* 1196: function trimSQL($str)
|
||
*
|
||
* SECTION: Compiling queries
|
||
* SECTION: Compiling queries
|
||
* 1225: function compileSQL($components)
|
||
* 1225: function compileSQL($components)
|
||
* 1263: function compileSELECT($components)
|
||
* 1263: function compileSELECT($components)
|
||
* 1294: function compileUPDATE($components)
|
||
* 1294: function compileUPDATE($components)
|
||
* 1322: function compileINSERT($components)
|
||
* 1322: function compileINSERT($components)
|
||
* 1362: function compileDELETE($components)
|
||
* 1362: function compileDELETE($components)
|
||
* 1382: function compileCREATETABLE($components)
|
||
* 1382: function compileCREATETABLE($components)
|
||
* 1415: function compileALTERTABLE($components)
|
||
* 1415: function compileALTERTABLE($components)
|
||
*
|
||
* SECTION: Compiling queries, helper functions for parts of queries
|
||
* SECTION: Compiling queries, helper functions for parts of queries
|
||
* 1468: function compileFieldList($selectFields)
|
||
* 1468: function compileFieldList($selectFields)
|
||
* 1510: function compileFromTables($tablesArray)
|
||
* 1510: function compileFromTables($tablesArray)
|
||
* 1551: function compileWhereClause($clauseArray)
|
||
* 1551: function compileWhereClause($clauseArray)
|
||
* 1605: function compileFieldCfg($fieldCfg)
|
||
* 1605: function compileFieldCfg($fieldCfg)
|
||
*
|
||
* SECTION: Debugging
|
||
* SECTION: Debugging
|
||
* 1654: function debug_parseSQLpart($part,$str)
|
||
* 1654: function debug_parseSQLpart($part,$str)
|
||
* 1679: function debug_parseSQLpartCompare($str,$newStr,$caseInsensitive=FALSE)
|
||
* 1679: function debug_parseSQLpartCompare($str,$newStr,$caseInsensitive=FALSE)
|
||
* 1712: function debug_testSQL($SQLquery)
|
||
* 1712: function debug_testSQL($SQLquery)
|
||
*
|
||
* TOTAL FUNCTIONS: 35
|
||
* (This index is automatically created/updated by the extension "extdeveval")
|
||
... | ... | |
*/
|
||
/**
|
||
* TYPO3 SQL parser class.
|
||
*
|
||
... | ... | |
class t3lib_sqlparser {
|
||
// Parser:
|
||
var $parse_error = ''; // Parsing error string
|
||
var $parse_error = ''; // Parsing error string
|
||
var $lastStopKeyWord = ''; // Last stop keyword used.
|
||
var $lastStopKeyWord = ''; // Last stop keyword used.
|
||
/*************************************
|
||
*
|
||
* SQL Parsing, full queries
|
||
... | ... | |
$result = array();
|
||
// Finding starting keyword of string:
|
||
$_parseString = $parseString; // Protecting original string...
|
||
$_parseString = $parseString; // Protecting original string...
|
||
$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|TRUNCATE[[:space:]]+TABLE)[[:space:]]+');
|
||
$keyword = strtoupper(str_replace(array(' ',TAB,CR,LF),'',$keyword));
|
||
$keyword = strtoupper(str_replace(array(' ', TAB, CR, LF), '', $keyword));
|
||
switch($keyword) {
|
||
switch ($keyword) {
|
||
case 'SELECT':
|
||
// Parsing SELECT query:
|
||
$result = $this->parseSELECT($parseString);
|
||
... | ... | |
$result = $this->parseTRUNCATETABLE($parseString);
|
||
break;
|
||
default:
|
||
$result = $this->parseError('"'.$keyword.'" is not a keyword',$parseString);
|
||
$result = $this->parseError('"' . $keyword . '" is not a keyword', $parseString);
|
||
break;
|
||
}
|
||
... | ... | |
// Removing SELECT:
|
||
$parseString = $this->trimSQL($parseString);
|
||
$parseString = ltrim(substr($parseString,6));
|
||
$parseString = ltrim(substr($parseString, 6));
|
||
// Init output variable:
|
||
$result = array();
|
||
... | ... | |
// Select fields:
|
||
$result['SELECT'] = $this->parseFieldList($parseString, '^(FROM)[[:space:]]+');
|
||
if ($this->parse_error) { return $this->parse_error; }
|
||
if ($this->parse_error) {
|
||
return $this->parse_error;
|
||
}
|
||
// Continue if string is not ended:
|
||
if ($parseString) {
|
||
if ($parseString) {
|
||
// Get table list:
|
||
$result['FROM'] = $this->parseFromTables($parseString, '^(WHERE)[[:space:]]+');
|
||
if ($this->parse_error) { return $this->parse_error; }
|
||
if ($this->parse_error) {
|
||
return $this->parse_error;
|
||
}
|
||
// If there are more than just the tables (a WHERE clause that would be...)
|
||
if ($parseString) {
|
||
if ($parseString) {
|
||
// Get WHERE clause:
|
||
$result['WHERE'] = $this->parseWhereClause($parseString, '^(GROUP[[:space:]]+BY|ORDER[[:space:]]+BY|LIMIT)[[:space:]]+', $parameterReferences);
|
||
if ($this->parse_error) { return $this->parse_error; }
|
||
if ($this->parse_error) {
|
||
return $this->parse_error;
|
||
}
|
||
// If the WHERE clause parsing was stopped by GROUP BY, ORDER BY or LIMIT, then proceed with parsing:
|
||
if ($this->lastStopKeyWord) {
|
||
if ($this->lastStopKeyWord) {
|
||
// GROUP BY parsing:
|
||
if ($this->lastStopKeyWord == 'GROUPBY') {
|
||
if ($this->lastStopKeyWord == 'GROUPBY') {
|
||
$result['GROUPBY'] = $this->parseFieldList($parseString, '^(ORDER[[:space:]]+BY|LIMIT)[[:space:]]+');
|
||
if ($this->parse_error) { return $this->parse_error; }
|
||
if ($this->parse_error) {
|
||
return $this->parse_error;
|
||
}
|
||
}
|
||
}
|
||
// ORDER BY parsing:
|
||
if ($this->lastStopKeyWord == 'ORDERBY') {
|
||
if ($this->lastStopKeyWord == 'ORDERBY') {
|
||
$result['ORDERBY'] = $this->parseFieldList($parseString, '^(LIMIT)[[:space:]]+');
|
||
if ($this->parse_error) { return $this->parse_error; }
|
||
if ($this->parse_error) {
|
||
return $this->parse_error;
|
||
}
|
||
}
|
||
}
|
||
// LIMIT parsing:
|
||
if ($this->lastStopKeyWord == 'LIMIT') {
|
||
if ($this->lastStopKeyWord == 'LIMIT') {
|
||
if (preg_match('/^([0-9]+|[0-9]+[[:space:]]*,[[:space:]]*[0-9]+)$/',trim($parseString))) {
|
||
if (preg_match('/^([0-9]+|[0-9]+[[:space:]]*,[[:space:]]*[0-9]+)$/', trim($parseString))) {
|
||
$result['LIMIT'] = $parseString;
|
||
} else {
|
||
return $this->parseError('No value for limit!',$parseString);
|
||
return $this->parseError('No value for limit!', $parseString);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
} else return $this->parseError('No table to select from!',$parseString);
|
||
} else {
|
||
return $this->parseError('No table to select from!', $parseString);
|
||
}
|
||
// Store current parseString in the result array for possible further processing (e.g., subquery support by DBAL)
|
||
$result['parseString'] = $parseString;
|
||
... | ... | |
// Removing UPDATE
|
||
$parseString = $this->trimSQL($parseString);
|
||
$parseString = ltrim(substr($parseString,6));
|
||
$parseString = ltrim(substr($parseString, 6));
|
||
// Init output variable:
|
||
$result = array();
|
||
... | ... | |
$result['TABLE'] = $this->nextPart($parseString, '^([[:alnum:]_]+)[[:space:]]+');
|
||
// Continue if string is not ended:
|
||
if ($result['TABLE']) {
|
||
if ($result['TABLE']) {
|
||
if ($parseString && $this->nextPart($parseString, '^(SET)[[:space:]]+')) {
|
||
if ($parseString && $this->nextPart($parseString, '^(SET)[[:space:]]+')) {
|
||
$comma = TRUE;
|
||
// Get field/value pairs:
|
||
while($comma) {
|
||
while ($comma) {
|
||
if ($fieldName = $this->nextPart($parseString,'^([[:alnum:]_]+)[[:space:]]*=')) {
|
||
if ($fieldName = $this->nextPart($parseString, '^([[:alnum:]_]+)[[:space:]]*=')) {
|
||
$this->nextPart($parseString,'^(=)'); // Strip of "=" sign.
|
||
$this->nextPart($parseString, '^(=)'); // Strip of "=" sign.
|
||
$value = $this->getValue($parseString);
|
||
$result['FIELDS'][$fieldName] = $value;
|
||
} else return $this->parseError('No fieldname found',$parseString);
|
||
} else {
|
||
return $this->parseError('No fieldname found', $parseString);
|
||
}
|
||
$comma = $this->nextPart($parseString,'^(,)');
|
||
$comma = $this->nextPart($parseString, '^(,)');
|
||
}
|
||
// WHERE
|
||
if ($this->nextPart($parseString,'^(WHERE)')) {
|
||
if ($this->nextPart($parseString, '^(WHERE)')) {
|
||
$result['WHERE'] = $this->parseWhereClause($parseString);
|
||
if ($this->parse_error) { return $this->parse_error; }
|
||
if ($this->parse_error) {
|
||
return $this->parse_error;
|
||
}
|
||
}
|
||
} else return $this->parseError('Query missing SET...',$parseString);
|
||
} else return $this->parseError('No table found!',$parseString);
|
||
}
|
||
} else {
|
||
return $this->parseError('Query missing SET...', $parseString);
|
||
}
|
||
} else {
|
||
return $this->parseError('No table found!', $parseString);
|
||
}
|
||
// Should be no more content now:
|
||
if ($parseString) {
|
||
if ($parseString) {
|
||
return $this->parseError('Still content in clause after parsing!',$parseString);
|
||
return $this->parseError('Still content in clause after parsing!', $parseString);
|
||
}
|
||
// Return result:
|
||
... | ... | |
// Removing INSERT
|
||
$parseString = $this->trimSQL($parseString);
|
||
$parseString = ltrim(substr(ltrim(substr($parseString,6)),4));
|
||
$parseString = ltrim(substr(ltrim(substr($parseString, 6)), 4));
|
||
// Init output variable:
|
||
$result = array();
|
||
... | ... | |
// Get table:
|
||
$result['TABLE'] = $this->nextPart($parseString, '^([[:alnum:]_]+)([[:space:]]+|\()');
|
||
if ($result['TABLE']) {
|
||
if ($result['TABLE']) {
|
||
if ($this->nextPart($parseString,'^(VALUES)([[:space:]]+|\()')) { // In this case there are no field names mentioned in the SQL!
|
||
if ($this->nextPart($parseString, '^(VALUES)([[:space:]]+|\()')) { // In this case there are no field names mentioned in the SQL!
|
||
// Get values/fieldnames (depending...)
|
||
$result['VALUES_ONLY'] = $this->getValue($parseString,'IN');
|
||
$result['VALUES_ONLY'] = $this->getValue($parseString, 'IN');
|
||
if ($this->parse_error) {
|
||
if ($this->parse_error) {
|
||
return $this->parse_error;
|
||
}
|
||
if (preg_match('/^,/', $parseString)) {
|
||
... | ... | |
$result['EXTENDED'] = '1';
|
||
while ($this->nextPart($parseString, '^(,)') === ',') {
|
||
$result['VALUES_ONLY'][] = $this->getValue($parseString, 'IN');
|
||
if ($this->parse_error) {
|
||
if ($this->parse_error) {
|
||
return $this->parse_error;
|
||
}
|
||
}
|
||
}
|
||
} else { // There are apparently fieldnames listed:
|
||
} else { // There are apparently fieldnames listed:
|
||
$fieldNames = $this->getValue($parseString,'_LIST');
|
||
$fieldNames = $this->getValue($parseString, '_LIST');
|
||
if ($this->parse_error) { return $this->parse_error; }
|
||
if ($this->parse_error) {
|
||
return $this->parse_error;
|
||
}
|
||
if ($this->nextPart($parseString,'^(VALUES)([[:space:]]+|\()')) { // "VALUES" keyword binds the fieldnames to values:
|
||
if ($this->nextPart($parseString, '^(VALUES)([[:space:]]+|\()')) { // "VALUES" keyword binds the fieldnames to values:
|
||
$result['FIELDS'] = array();
|
||
do {
|
||
$values = $this->getValue($parseString, 'IN'); // Using the "getValue" function to get the field list...
|
||
$values = $this->getValue($parseString, 'IN'); // Using the "getValue" function to get the field list...
|
||
if ($this->parse_error) {
|
||
if ($this->parse_error) {
|
||
return $this->parse_error;
|
||
}
|
||
$insertValues = array();
|
||
foreach ($fieldNames as $k => $fN) {
|
||
if (preg_match('/^[[:alnum:]_]+$/', $fN)) {
|
||
if (isset($values[$k])) {
|
||
if (isset($values[$k])) {
|
||
if (!isset($insertValues[$fN])) {
|
||
$insertValues[$fN] = $values[$k];
|
||
} else return $this->parseError('Fieldname ("' . $fN . '") already found in list!', $parseString);
|
||
} else return $this->parseError('No value set!', $parseString);
|
||
} else return $this->parseError('Invalid fieldname ("' . $fN . '")', $parseString);
|
||
} else {
|
||
return $this->parseError('Fieldname ("' . $fN . '") already found in list!', $parseString);
|
||
}
|
||
}
|
||
} else {
|
||
return $this->parseError('No value set!', $parseString);
|
||
}
|
||
} else {
|
||
return $this->parseError('Invalid fieldname ("' . $fN . '")', $parseString);
|
||
}
|
||
}
|
||
if (isset($values[$k + 1])) {
|
||
return $this->parseError('Too many values in list!', $parseString);
|
||
}
|
||
... | ... | |
} else {
|
||
$result['EXTENDED'] = '1';
|
||
}
|
||
} else return $this->parseError('VALUES keyword expected',$parseString);
|
||
} else {
|
||
return $this->parseError('VALUES keyword expected', $parseString);
|
||
}
|
||
}
|
||
} else return $this->parseError('No table found!',$parseString);
|
||
}
|
||
} else {
|
||
return $this->parseError('No table found!', $parseString);
|
||
}
|
||
// Should be no more content now:
|
||
if ($parseString) {
|
||
if ($parseString) {
|
||
return $this->parseError('Still content after parsing!',$parseString);
|
||
return $this->parseError('Still content after parsing!', $parseString);
|
||
}
|
||
// Return result
|
||
... | ... | |
// Removing DELETE
|
||
$parseString = $this->trimSQL($parseString);
|
||
$parseString = ltrim(substr(ltrim(substr($parseString,6)),4));
|
||
$parseString = ltrim(substr(ltrim(substr($parseString, 6)), 4));
|
||
// Init output variable:
|
||
$result = array();
|
||
... | ... | |
// Get table:
|
||
$result['TABLE'] = $this->nextPart($parseString, '^([[:alnum:]_]+)[[:space:]]+');
|
||
if ($result['TABLE']) {
|
||
if ($result['TABLE']) {
|
||
// WHERE
|
||
if ($this->nextPart($parseString,'^(WHERE)')) {
|
||
if ($this->nextPart($parseString, '^(WHERE)')) {
|
||
$result['WHERE'] = $this->parseWhereClause($parseString);
|
||
if ($this->parse_error) { return $this->parse_error; }
|
||
if ($this->parse_error) {
|
||
return $this->parse_error;
|
||
}
|
||
}
|
||
} else return $this->parseError('No table found!',$parseString);
|
||
}
|
||
} else {
|
||
return $this->parseError('No table found!', $parseString);
|
||
}
|
||
// Should be no more content now:
|
||
if ($parseString) {
|
||
if ($parseString) {
|
||
return $this->parseError('Still content in clause after parsing!',$parseString);
|
||
return $this->parseError('Still content in clause after parsing!', $parseString);
|
||
}
|
||
// Return result:
|
||
... | ... | |
// Removing EXPLAIN
|
||
$parseString = $this->trimSQL($parseString);
|
||
$parseString = ltrim(substr($parseString,6));
|
||
$parseString = ltrim(substr($parseString, 6));
|
||
// Init output variable:
|
||
$result = $this->parseSELECT($parseString);
|
||
if (is_array($result)) {
|
||
if (is_array($result)) {
|
||
$result['type'] = 'EXPLAIN';
|
||
}
|
||
... | ... | |
// Removing CREATE TABLE
|
||
$parseString = $this->trimSQL($parseString);
|
||
$parseString = ltrim(substr(ltrim(substr($parseString,6)),5));
|
||
$parseString = ltrim(substr(ltrim(substr($parseString, 6)), 5));
|
||
// Init output variable:
|
||
$result = array();
|
||
$result['type'] = 'CREATETABLE';
|
||
// Get table:
|
||
$result['TABLE'] = $this->nextPart($parseString, '^([[:alnum:]_]+)[[:space:]]*\(',TRUE);
|
||
$result['TABLE'] = $this->nextPart($parseString, '^([[:alnum:]_]+)[[:space:]]*\(', TRUE);
|
||
if ($result['TABLE']) {
|
||
if ($result['TABLE']) {
|
||
// While the parseString is not yet empty:
|
||
while(strlen($parseString)>0) {
|
||
while (strlen($parseString) > 0) {
|
||
if ($key = $this->nextPart($parseString, '^(KEY|PRIMARY KEY|UNIQUE KEY|UNIQUE)([[:space:]]+|\()')) { // Getting key
|
||
if ($key = $this->nextPart($parseString, '^(KEY|PRIMARY KEY|UNIQUE KEY|UNIQUE)([[:space:]]+|\()')) { // Getting key
|
||
$key = strtoupper(str_replace(array(' ',TAB,CR,LF),'',$key));
|
||
$key = strtoupper(str_replace(array(' ', TAB, CR, LF), '', $key));
|
||
switch($key) {
|
||
switch ($key) {
|
||
case 'PRIMARYKEY':
|
||
$result['KEYS']['PRIMARYKEY'] = $this->getValue($parseString,'_LIST');
|
||
$result['KEYS']['PRIMARYKEY'] = $this->getValue($parseString, '_LIST');
|
||
if ($this->parse_error) { return $this->parse_error; }
|
||
if ($this->parse_error) {
|
||
return $this->parse_error;
|
||
}
|
||
break;
|
||
case 'UNIQUE':
|
||
case 'UNIQUEKEY':
|
||
if ($keyName = $this->nextPart($parseString, '^([[:alnum:]_]+)([[:space:]]+|\()')) {
|
||
if ($keyName = $this->nextPart($parseString, '^([[:alnum:]_]+)([[:space:]]+|\()')) {
|
||
$result['KEYS']['UNIQUE'] = array($keyName => $this->getValue($parseString,'_LIST'));
|
||
$result['KEYS']['UNIQUE'] = array($keyName => $this->getValue($parseString, '_LIST'));
|
||
if ($this->parse_error) { return $this->parse_error; }
|
||
} else return $this->parseError('No keyname found',$parseString);
|
||
if ($this->parse_error) {
|
||
return $this->parse_error;
|
||
}
|
||
} else {
|
||
return $this->parseError('No keyname found', $parseString);
|
||
}
|
||
break;
|
||
case 'KEY':
|
||
if ($keyName = $this->nextPart($parseString, '^([[:alnum:]_]+)([[:space:]]+|\()')) {
|
||
if ($keyName = $this->nextPart($parseString, '^([[:alnum:]_]+)([[:space:]]+|\()')) {
|
||
$result['KEYS'][$keyName] = $this->getValue($parseString, '_LIST', 'INDEX');
|
||
if ($this->parse_error) { return $this->parse_error; }
|
||
} else return $this->parseError('No keyname found',$parseString);
|
||
if ($this->parse_error) {
|
||
return $this->parse_error;
|
||
}
|
||
} else {
|
||
return $this->parseError('No keyname found', $parseString);
|
||
}
|
||
break;
|
||
}
|
||
} elseif ($fieldName = $this->nextPart($parseString, '^([[:alnum:]_]+)[[:space:]]+')) { // Getting field:
|
||
} elseif ($fieldName = $this->nextPart($parseString, '^([[:alnum:]_]+)[[:space:]]+')) { // Getting field:
|
||
$result['FIELDS'][$fieldName]['definition'] = $this->parseFieldDef($parseString);
|
||
if ($this->parse_error) { return $this->parse_error; }
|
||
if ($this->parse_error) {
|
||
return $this->parse_error;
|
||
}
|
||
}
|
||
}
|
||
// Finding delimiter:
|
||
$delim = $this->nextPart($parseString, '^(,|\))');
|
||
if (!$delim) {
|
||
if (!$delim) {
|
||
return $this->parseError('No delimiter found',$parseString);
|
||
return $this->parseError('No delimiter found', $parseString);
|
||
} elseif ($delim==')') {
|
||
} elseif ($delim == ')') {
|
||
break;
|
||
}
|
||
}
|
||
// Finding what is after the table definition - table type in MySQL
|
||
if ($delim==')') {
|
||
if ($delim == ')') {
|
||
if ($this->nextPart($parseString, '^((ENGINE|TYPE)[[:space:]]*=)')) {
|
||
if ($this->nextPart($parseString, '^((ENGINE|TYPE)[[:space:]]*=)')) {
|
||
$result['tableType'] = $parseString;
|
||
$parseString = '';
|
||
}
|
||
} else return $this->parseError('No fieldname found!',$parseString);
|
||
} else {
|
||
return $this->parseError('No fieldname found!', $parseString);
|
||
}
|
||
// Getting table type
|
||
// Getting table type
|
||
} else return $this->parseError('No table found!',$parseString);
|
||
} else {
|
||
return $this->parseError('No table found!', $parseString);
|
||
}
|
||
// Should be no more content now:
|
||
if ($parseString) {
|
||
if ($parseString) {
|
||
return $this->parseError('Still content in clause after parsing!',$parseString);
|
||
return $this->parseError('Still content in clause after parsing!', $parseString);
|
||
}
|
||
return $result;
|
||
... | ... | |
// Removing ALTER TABLE
|
||
$parseString = $this->trimSQL($parseString);
|
||
$parseString = ltrim(substr(ltrim(substr($parseString,5)),5));
|
||
$parseString = ltrim(substr(ltrim(substr($parseString, 5)), 5));
|
||
// Init output variable:
|
||
$result = array();
|
||
... | ... | |
return $this->parseError('No end backquote found!', $parseString);
|
||
}
|
||
if ($result['TABLE']) {
|
||
if ($result['TABLE']) {
|
||
if ($result['action'] = $this->nextPart($parseString, '^(CHANGE|DROP[[:space:]]+KEY|DROP[[:space:]]+PRIMARY[[:space:]]+KEY|ADD[[:space:]]+KEY|ADD[[:space:]]+PRIMARY[[:space:]]+KEY|ADD[[:space:]]+UNIQUE|DROP|ADD|RENAME|DEFAULT[[:space:]]+CHARACTER[[:space:]]+SET|ENGINE)([[:space:]]+|\(|=)')) {
|
||
if ($result['action'] = $this->nextPart($parseString, '^(CHANGE|DROP[[:space:]]+KEY|DROP[[:space:]]+PRIMARY[[:space:]]+KEY|ADD[[:space:]]+KEY|ADD[[:space:]]+PRIMARY[[:space:]]+KEY|ADD[[:space:]]+UNIQUE|DROP|ADD|RENAME|DEFAULT[[:space:]]+CHARACTER[[:space:]]+SET|ENGINE)([[:space:]]+|\(|=)')) {
|
||
$actionKey = strtoupper(str_replace(array(' ',TAB,CR,LF),'',$result['action']));
|
||
$actionKey = strtoupper(str_replace(array(' ', TAB, CR, LF), '', $result['action']));
|
||
// Getting field:
|
||
if (t3lib_div::inList('ADDPRIMARYKEY,DROPPRIMARYKEY,ENGINE', $actionKey) || $fieldKey = $this->nextPart($parseString, '^([[:alnum:]_]+)[[:space:]]+')) {
|
||
switch($actionKey) {
|
||
switch ($actionKey) {
|
||
case 'ADD':
|
||
$result['FIELD'] = $fieldKey;
|
||
$result['definition'] = $this->parseFieldDef($parseString);
|
||
if ($this->parse_error) { return $this->parse_error; }
|
||
if ($this->parse_error) {
|
||
return $this->parse_error;
|
||
}
|
||
break;
|
||
case 'DROP':
|
||
case 'RENAME':
|
||
... | ... | |
break;
|
||
case 'CHANGE':
|
||
$result['FIELD'] = $fieldKey;
|
||
if ($result['newField'] = $this->nextPart($parseString, '^([[:alnum:]_]+)[[:space:]]+')) {
|
||
if ($result['newField'] = $this->nextPart($parseString, '^([[:alnum:]_]+)[[:space:]]+')) {
|
||
$result['definition'] = $this->parseFieldDef($parseString);
|
||
if ($this->parse_error) { return $this->parse_error; }
|
||
} else return $this->parseError('No NEW field name found',$parseString);
|
||
if ($this->parse_error) {
|
||
return $this->parse_error;
|
||
}
|
||
} else {
|
||
return $this->parseError('No NEW field name found', $parseString);
|
||
}
|
||
break;
|
||
case 'ADDKEY':
|
||
... | ... | |
case 'ADDUNIQUE':
|
||
$result['KEY'] = $fieldKey;
|
||
$result['fields'] = $this->getValue($parseString, '_LIST', 'INDEX');
|
||
if ($this->parse_error) { return $this->parse_error; }
|
||
if ($this->parse_error) {
|
||
return $this->parse_error;
|
||
}
|
||
break;
|
||
case 'DROPKEY':
|
||
$result['KEY'] = $fieldKey;
|
||
break;
|
||
case 'DROPPRIMARYKEY':
|
||
// ??? todo!
|
||
// ??? todo!
|
||
break;
|
||
case 'DEFAULTCHARACTERSET':
|
||
$result['charset'] = $fieldKey;
|
||
... | ... | |
$result['engine'] = $this->nextPart($parseString, '^=[[:space:]]*([[:alnum:]]+)[[:space:]]+', TRUE);
|
||
break;
|
||
}
|
||
} else return $this->parseError('No field name found',$parseString);
|
||
} else return $this->parseError('No action CHANGE, DROP or ADD found!',$parseString);
|
||
} else return $this->parseError('No table found!',$parseString);
|
||
} else {
|
||
return $this->parseError('No field name found', $parseString);
|
||
}
|
||
} else {
|
||
return $this->parseError('No action CHANGE, DROP or ADD found!', $parseString);
|
||
}
|
||
} else {
|
||
return $this->parseError('No table found!', $parseString);
|
||
}
|
||
// Should be no more content now:
|
||
if ($parseString) {
|
||
if ($parseString) {
|
||
return $this->parseError('Still content in clause after parsing!',$parseString);
|
||
return $this->parseError('Still content in clause after parsing!', $parseString);
|
||
}
|
||
return $result;
|
||
... | ... | |
// Removing DROP TABLE
|
||
$parseString = $this->trimSQL($parseString);
|
||
$parseString = ltrim(substr(ltrim(substr($parseString,4)),5));
|
||
$parseString = ltrim(substr(ltrim(substr($parseString, 4)), 5));
|
||
// Init output variable:
|
||
$result = array();
|
||
$result['type'] = 'DROPTABLE';
|
||
// IF EXISTS
|
||
$result['ifExists'] = $this->nextPart($parseString, '^(IF[[:space:]]+EXISTS[[:space:]]+)');
|
||
$result['ifExists'] = $this->nextPart($parseString, '^(IF[[:space:]]+EXISTS[[:space:]]+)');
|
||
// Get table:
|
||
$result['TABLE'] = $this->nextPart($parseString, '^([[:alnum:]_]+)[[:space:]]+');
|
||
if ($result['TABLE']) {
|
||
if ($result['TABLE']) {
|
||
// Should be no more content now:
|
||
if ($parseString) {
|
||
if ($parseString) {
|
||
return $this->parseError('Still content in clause after parsing!',$parseString);
|
||
return $this->parseError('Still content in clause after parsing!', $parseString);
|
||
}
|
||
return $result;
|
||
} else return $this->parseError('No table found!',$parseString);
|
||
} else {
|
||
return $this->parseError('No table found!', $parseString);
|
||
}
|
||
}
|
||
}
|
||
/**
|
||
* Parsing CREATE DATABASE query
|
||
... | ... | |
// Removing CREATE DATABASE
|
||
$parseString = $this->trimSQL($parseString);
|
||
$parseString = ltrim(substr(ltrim(substr($parseString,6)),8));
|
||
$parseString = ltrim(substr(ltrim(substr($parseString, 6)), 8));
|
||
// Init output variable:
|
||
$result = array();
|
||
... | ... | |
// Get table:
|
||
$result['DATABASE'] = $this->nextPart($parseString, '^([[:alnum:]_]+)[[:space:]]+');
|
||
if ($result['DATABASE']) {
|
||
if ($result['DATABASE']) {
|
||
// Should be no more content now:
|
||
if ($parseString) {
|
||
if ($parseString) {
|
||
return $this->parseError('Still content in clause after parsing!',$parseString);
|
||
return $this->parseError('Still content in clause after parsing!', $parseString);
|
||
}
|
||
return $result;
|
||
} else return $this->parseError('No database found!',$parseString);
|
||
} else {
|
||
return $this->parseError('No database found!', $parseString);
|
||
}
|
||
}
|
||
}
|
||
/**
|
||
* Parsing TRUNCATE TABLE query
|
||
... | ... | |
}
|
||
/**************************************
|
||
*
|
||
* SQL Parsing, helper functions for parts of queries
|
||
... | ... | |
*/
|
||
public function parseFieldList(&$parseString, $stopRegex = '') {
|
||
$stack = array(); // Contains the parsed content
|
||
$stack = array(); // Contains the parsed content
|
||
if(strlen($parseString)==0) return $stack; // FIXME - should never happen, why does it?
|
||
if (strlen($parseString) == 0) {
|
||
return $stack;
|
||
} // FIXME - should never happen, why does it?
|
||
$pnt = 0; // Pointer to positions in $stack
|
||
$pnt = 0; // Pointer to positions in $stack
|
||
$level = 0; // Indicates the parenthesis level we are at.
|
||
$level = 0; // Indicates the parenthesis level we are at.
|
||
$loopExit = 0; // Recursivity brake.
|
||
$loopExit = 0; // Recursivity brake.
|
||
// Prepare variables:
|
||
$parseString = $this->trimSQL($parseString);
|
||
... | ... | |
while (strlen($parseString)) {
|
||
// Checking if we are inside / outside parenthesis (in case of a function like count(), max(), min() etc...):
|
||
if ($level>0) { // Inside parenthesis here (does NOT detect if values in quotes are used, the only token is ")" or "("):
|
||
if ($level > 0) { // Inside parenthesis here (does NOT detect if values in quotes are used, the only token is ")" or "("):
|
||
// Accumulate function content until next () parenthesis:
|
||
$funcContent = $this->nextPart($parseString,'^([^()]*.)');
|
||
$funcContent = $this->nextPart($parseString, '^([^()]*.)');
|
||
$stack[$pnt]['func_content.'][] = array(
|
||
'level' => $level,
|
||
'func_content' => substr($funcContent,0,-1)
|
||
'func_content' => substr($funcContent, 0, -1)
|
||
);
|
||
$stack[$pnt]['func_content'].= $funcContent;
|
||
$stack[$pnt]['func_content'] .= $funcContent;
|
||
// Detecting ( or )
|
||
switch(substr($stack[$pnt]['func_content'],-1)) {
|
||
switch (substr($stack[$pnt]['func_content'], -1)) {
|
||
case '(':
|
||
$level++;
|
||
break;
|
||
case ')':
|
||
$level--;
|
||
if (!$level) { // If this was the last parenthesis:
|
||
if (!$level) { // If this was the last parenthesis:
|
||
$stack[$pnt]['func_content'] = substr($stack[$pnt]['func_content'],0,-1);
|
||
$stack[$pnt]['func_content'] = substr($stack[$pnt]['func_content'], 0, -1);
|
||
$parseString = ltrim($parseString); // Remove any whitespace after the parenthesis.
|
||
$parseString = ltrim($parseString); // Remove any whitespace after the parenthesis.
|
||
}
|
||
break;
|
||
}
|
||
} else { // Outside parenthesis, looking for next field:
|
||
} else { // Outside parenthesis, looking for next field:
|
||
// Looking for a flow-control construct (only known constructs supported)
|
||
if (preg_match('/^case([[:space:]][[:alnum:]\*._]+)?[[:space:]]when/i', $parseString)) {
|
||
... | ... | |
}
|
||
} else {
|
||
// Looking for a known function (only known functions supported)
|
||
$func = $this->nextPart($parseString,'^(count|max|min|floor|sum|avg)[[:space:]]*\(');
|
||
$func = $this->nextPart($parseString, '^(count|max|min|floor|sum|avg)[[:space:]]*\(');
|
||
if ($func) {
|
||
if ($func) {
|
||
$parseString = trim(substr($parseString,1)); // Strip of "("
|
||
$parseString = trim(substr($parseString, 1)); // Strip of "("
|
||
$stack[$pnt]['type'] = 'function';
|
||
$stack[$pnt]['function'] = $func;
|
||
$level++; // increse parenthesis level counter.
|
||
$level++; // increse parenthesis level counter.
|
||
} else {
|
||
$stack[$pnt]['distinct'] = $this->nextPart($parseString,'^(distinct[[:space:]]+)');
|
||
$stack[$pnt]['distinct'] = $this->nextPart($parseString, '^(distinct[[:space:]]+)');
|
||
// Otherwise, look for regular fieldname:
|
||
if (($fieldName = $this->nextPart($parseString, '^([[:alnum:]\*._]+)(,|[[:space:]]+)')) !== '') {
|
||
$stack[$pnt]['type'] = 'field';
|
||
// Explode fieldname into field and table:
|
||
$tableField = explode('.',$fieldName,2);
|
||
$tableField = explode('.', $fieldName, 2);
|
||
if (count($tableField)==2) {
|
||
if (count($tableField) == 2) {
|
||
$stack[$pnt]['table'] = $tableField[0];
|
||
$stack[$pnt]['field'] = $tableField[1];
|
||
} else {
|
||
... | ... | |
$stack[$pnt]['field'] = $tableField[0];
|
||
}
|
||
} else {
|
||
return $this->parseError('No field name found as expected in parseFieldList()',$parseString);
|
||
return $this->parseError('No field name found as expected in parseFieldList()', $parseString);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
// After a function or field we look for "AS" alias and a comma to separate to the next field in the list:
|
||
if (!$level) {
|
||
if (!$level) {
|
||
// Looking for "AS" alias:
|
||
if ($as = $this->nextPart($parseString,'^(AS)[[:space:]]+')) {
|
||
if ($as = $this->nextPart($parseString, '^(AS)[[:space:]]+')) {
|
||
$stack[$pnt]['as'] = $this->nextPart($parseString,'^([[:alnum:]_]+)(,|[[:space:]]+)');
|
||
$stack[$pnt]['as'] = $this->nextPart($parseString, '^([[:alnum:]_]+)(,|[[:space:]]+)');
|
||
$stack[$pnt]['as_keyword'] = $as;
|
||
}
|
||
// Looking for "ASC" or "DESC" keywords (for ORDER BY)
|
||
if ($sDir = $this->nextPart($parseString,'^(ASC|DESC)([[:space:]]+|,)')) {
|
||
if ($sDir = $this->nextPart($parseString, '^(ASC|DESC)([[:space:]]+|,)')) {
|
||
$stack[$pnt]['sortDir'] = $sDir;
|
||
}
|
||
// Looking for stop-keywords:
|
||
if ($stopRegex && $this->lastStopKeyWord = $this->nextPart($parseString, $stopRegex)) {
|
||
if ($stopRegex && $this->lastStopKeyWord = $this->nextPart($parseString, $stopRegex)) {
|
||
$this->lastStopKeyWord = strtoupper(str_replace(array(' ',TAB,CR,LF),'',$this->lastStopKeyWord));
|
||
$this->lastStopKeyWord = strtoupper(str_replace(array(' ', TAB, CR, LF), '', $this->lastStopKeyWord));
|
||
return $stack;
|
||
}
|
||
// Looking for comma (since the stop-keyword did not trigger a return...)
|
||
if (strlen($parseString) && !$this->nextPart($parseString,'^(,)')) {
|
||
if (strlen($parseString) && !$this->nextPart($parseString, '^(,)')) {
|
||
return $this->parseError('No comma found as expected in parseFieldList()',$parseString);
|
||
return $this->parseError('No comma found as expected in parseFieldList()', $parseString);
|
||
}
|
||
// Increasing pointer:
|
||
... | ... | |
// Check recursivity brake:
|
||
$loopExit++;
|
||
if ($loopExit>500) {
|
||
if ($loopExit > 500) {
|
||
return $this->parseError('More than 500 loops, exiting prematurely in parseFieldList()...',$parseString);
|
||
return $this->parseError('More than 500 loops, exiting prematurely in parseFieldList()...', $parseString);
|
||
}
|
||
}
|
||
... | ... | |
$this->lastStopKeyWord = '';
|
||
$this->parse_error = '';
|
||
$stack = array(); // Contains the parsed content
|
||
$stack = array(); // Contains the parsed content
|
||
$pnt = 0; // Pointer to positions in $stack
|
||
$pnt = 0; // Pointer to positions in $stack
|
||
$loopExit = 0; // Recursivity brake.
|
||
$loopExit = 0; // Recursivity brake.
|
||
// $parseString is continously shortend by the process and we keep parsing it till it is zero:
|
||
while (strlen($parseString)) {
|
||
// Looking for the table:
|
||
if ($stack[$pnt]['table'] = $this->nextPart($parseString,'^([[:alnum:]_]+)(,|[[:space:]]+)')) {
|
||
if ($stack[$pnt]['table'] = $this->nextPart($parseString, '^([[:alnum:]_]+)(,|[[:space:]]+)')) {
|
||
// Looking for stop-keywords before fetching potential table alias:
|
||
if ($stopRegex && ($this->lastStopKeyWord = $this->nextPart($parseString, $stopRegex))) {
|
||
$this->lastStopKeyWord = strtoupper(str_replace(array(' ',TAB,CR,LF), '', $this->lastStopKeyWord));
|
||
$this->lastStopKeyWord = strtoupper(str_replace(array(' ', TAB, CR, LF), '', $this->lastStopKeyWord));
|
||
return $stack;
|
||
}
|
||
if (!preg_match('/^(LEFT|RIGHT|JOIN|INNER)[[:space:]]+/i', $parseString)) {
|
||
$stack[$pnt]['as_keyword'] = $this->nextPart($parseString,'^(AS[[:space:]]+)');
|
||
$stack[$pnt]['as_keyword'] = $this->nextPart($parseString, '^(AS[[:space:]]+)');
|
||
$stack[$pnt]['as'] = $this->nextPart($parseString,'^([[:alnum:]_]+)[[:space:]]*');
|
||
$stack[$pnt]['as'] = $this->nextPart($parseString, '^([[:alnum:]_]+)[[:space:]]*');
|
||
}
|
||
} else return $this->parseError('No table name found as expected in parseFromTables()!', $parseString);
|
||
} else {
|
||
return $this->parseError('No table name found as expected in parseFromTables()!', $parseString);
|
||
}
|
||
// Looking for JOIN
|
||
$joinCnt = 0;
|
||
while ($join = $this->nextPart($parseString,'^(LEFT[[:space:]]+JOIN|LEFT[[:space:]]+OUTER[[:space:]]+JOIN|RIGHT[[:space:]]+JOIN|RIGHT[[:space:]]+OUTER[[:space:]]+JOIN|INNER[[:space:]]+JOIN|JOIN)[[:space:]]+')) {
|
||
while ($join = $this->nextPart($parseString, '^(LEFT[[:space:]]+JOIN|LEFT[[:space:]]+OUTER[[:space:]]+JOIN|RIGHT[[:space:]]+JOIN|RIGHT[[:space:]]+OUTER[[:space:]]+JOIN|INNER[[:space:]]+JOIN|JOIN)[[:space:]]+')) {
|
||
$stack[$pnt]['JOIN'][$joinCnt]['type'] = $join;
|
||
if ($stack[$pnt]['JOIN'][$joinCnt]['withTable'] = $this->nextPart($parseString, '^([[:alnum:]_]+)[[:space:]]+', 1)) {
|
||
if (!preg_match('/^ON[[:space:]]+/i', $parseString)) {
|
||
... | ... | |
}
|
||
}
|
||
$joinCnt++;
|
||
} else return $this->parseError('No join table found in parseFromTables()!', $parseString);
|
||
} else {
|
||
return $this->parseError('No join table found in parseFromTables()!', $parseString);
|
||
}
|
||
}
|
||
}
|
||
// Looking for stop-keywords:
|
||
if ($stopRegex && $this->lastStopKeyWord = $this->nextPart($parseString, $stopRegex)) {
|
||
$this->lastStopKeyWord = strtoupper(str_replace(array(' ',TAB,CR,LF), '', $this->lastStopKeyWord));
|
||
$this->lastStopKeyWord = strtoupper(str_replace(array(' ', TAB, CR, LF), '', $this->lastStopKeyWord));
|
||
return $stack;
|
||
}
|
||
... | ... | |
$this->lastStopKeyWord = '';
|
||
$this->parse_error = '';
|
||
$stack = array(0 => array()); // Contains the parsed content
|
||
$stack = array(0 => array()); // Contains the parsed content
|
||
$pnt = array(0 => 0); // Pointer to positions in $stack
|
||
$pnt = array(0 => 0); // Pointer to positions in $stack
|
||
$level = 0; // Determines parenthesis level
|
||
$level = 0; // Determines parenthesis level
|
||
$loopExit = 0; // Recursivity brake.
|
||
$loopExit = 0; // Recursivity brake.
|
||
// $parseString is continously shortend by the process and we keep parsing it till it is zero:
|
||
while (strlen($parseString)) {
|
||
// Look for next parenthesis level:
|
||
$newLevel = $this->nextPart($parseString,'^([(])');
|
||
$newLevel = $this->nextPart($parseString, '^([(])');
|
||
if ($newLevel == '(') { // If new level is started, manage stack/pointers:
|
||
if ($newLevel == '(') { // If new level is started, manage stack/pointers:
|
||
$level++; // Increase level
|
||
$level++; // Increase level
|
||
$pnt[$level] = 0; // Reset pointer for this level
|
||
$pnt[$level] = 0; // Reset pointer for this level
|
||
$stack[$level] = array(); // Reset stack for this level
|
||
$stack[$level] = array(); // Reset stack for this level
|
||
} else { // If no new level is started, just parse the current level:
|
||
} else { // If no new level is started, just parse the current level:
|
||
// Find "modifier", eg. "NOT or !"
|
||
$stack[$level][$pnt[$level]]['modifier'] = trim($this->nextPart($parseString, '^(!|NOT[[:space:]]+)'));
|
||
... | ... | |
// See if condition is EXISTS with a subquery
|
||
if (preg_match('/^EXISTS[[:space:]]*[(]/i', $parseString)) {
|
||
$stack[$level][$pnt[$level]]['func']['type'] = $this->nextPart($parseString, '^(EXISTS)[[:space:]]*');
|
||
$parseString = trim(substr($parseString, 1)); // Strip of "("
|
||
$parseString = trim(substr($parseString, 1)); // Strip of "("
|
||
$stack[$level][$pnt[$level]]['func']['subquery'] = $this->parseSELECT($parseString, $parameterReferences);
|
||
// Seek to new position in parseString after parsing of the subquery
|
||
$parseString = $stack[$level][$pnt[$level]]['func']['subquery']['parseString'];
|
||
unset($stack[$level][$pnt[$level]]['func']['subquery']['parseString']);
|
||
if (!$this->nextPart($parseString, '^([)])')) {
|
||
return 'No ) parenthesis at end of subquery';
|
||
}
|
||
} else {
|
||
}
|
||
} else {
|
||
// See if LOCATE function is found
|
||
// See if LOCATE function is found
|
||
if (preg_match('/^LOCATE[[:space:]]*[(]/i', $parseString)) {
|
||
$stack[$level][$pnt[$level]]['func']['type'] = $this->nextPart($parseString, '^(LOCATE)[[:space:]]*');
|
||
$parseString = trim(substr($parseString, 1)); // Strip of "("
|
||
$parseString = trim(substr($parseString, 1)); // Strip of "("
|
||
$stack[$level][$pnt[$level]]['func']['substr'] = $this->getValue($parseString);
|
||
if (!$this->nextPart($parseString, '^(,)')) {
|
||
return $this->parseError('No comma found as expected in parseWhereClause()', $parseString);
|
||
... | ... | |
$stack[$level][$pnt[$level]]['func']['table'] = '';
|
||
$stack[$level][$pnt[$level]]['func']['field'] = $tableField[0];
|
||
}
|
||
} else {
|
||
} else {
|
||
return $this->parseError('No field name found as expected in parseWhereClause()', $parseString);
|
||
}
|
||
}
|
||
if ($this->nextPart($parseString, '^(,)')) {
|
||
$stack[$level][$pnt[$level]]['func']['pos'] = $this->getValue($parseString);
|
||
}
|
||
if (!$this->nextPart($parseString, '^([)])')) {
|
||
return $this->parseError('No ) parenthesis at end of function', $parseString);
|
||
}
|
||
}
|
||
} elseif (preg_match('/^IFNULL[[:space:]]*[(]/i', $parseString)) {
|
||
$stack[$level][$pnt[$level]]['func']['type'] = $this->nextPart($parseString, '^(IFNULL)[[:space:]]*');
|
||
$parseString = trim(substr($parseString, 1)); // Strip of "("
|
||
$parseString = trim(substr($parseString, 1)); // Strip of "("
|
||
if ($fieldName = $this->nextPart($parseString, '^([[:alnum:]\*._]+)[[:space:]]*')) {
|
||
// Parse field name into field and table:
|
||
... | ... | |
$stack[$level][$pnt[$level]]['func']['table'] = '';
|
||
$stack[$level][$pnt[$level]]['func']['field'] = $tableField[0];
|
||
}
|
||
} else {
|
||
} else {
|
||
return $this->parseError('No field name found as expected in parseWhereClause()', $parseString);
|
||
}
|
||
}
|
||
if ($this->nextPart($parseString, '^(,)')) {
|
||
$stack[$level][$pnt[$level]]['func']['default'] = $this->getValue($parseString);
|
||
}
|
||
if (!$this->nextPart($parseString, '^([)])')) {
|
||
return $this->parseError('No ) parenthesis at end of function', $parseString);
|
||
}
|
||
}
|
||
} elseif (preg_match('/^FIND_IN_SET[[:space:]]*[(]/i', $parseString)) {
|
||
$stack[$level][$pnt[$level]]['func']['type'] = $this->nextPart($parseString, '^(FIND_IN_SET)[[:space:]]*');
|
||
$parseString = trim(substr($parseString, 1)); // Strip of "("
|
||
$parseString = trim(substr($parseString, 1)); // Strip of "("
|
||
if ($str = $this->getValue($parseString)) {
|
||
$stack[$level][$pnt[$level]]['func']['str'] = $str;
|
||
if ($fieldName = $this->nextPart($parseString, '^,[[:space:]]*([[:alnum:]._]+)[[:space:]]*', TRUE)) {
|
||
... | ... | |
}
|
||
if (!$this->nextPart($parseString, '^([)])')) {
|
||
return $this->parseError('No ) parenthesis at end of function', $parseString);
|
||
}
|
||
}
|
||
} else {
|
||
return $this->parseError('No item to look for found as expected in parseWhereClause()', $parseString);
|
||
}
|
||
} else {
|
||
} else {
|
||
// Support calculated value only for:
|
||
// Support calculated value only for:
|
||
// - "&" (boolean AND)
|
||
// - "+" (addition)
|
||
// - "-" (substraction)
|
||
... | ... | |
// Parse field name into field and table:
|
||
$tableField = explode('.', $fieldName, 2);
|
||
if (count($tableField) == 2) {
|
||
if (count($tableField) == 2) {
|
||
$stack[$level][$pnt[$level]]['table'] = $tableField[0];
|
||
$stack[$level][$pnt[$level]]['field'] = $tableField[1];
|
||
} else {
|
||
} else {
|
||
$stack[$level][$pnt[$level]]['table'] = '';
|
||
$stack[$level][$pnt[$level]]['field'] = $tableField[0];
|
||
}
|
||
}
|
||
} else {
|
||
return $this->parseError('No field name found as expected in parseWhereClause()', $parseString);
|
||
}
|
||
}
|
||
// See if the value is calculated:
|
||
$stack[$level][$pnt[$level]]['calc'] = $this->nextPart($parseString, '^(' . $calcOperators . ')');
|
||
... | ... | |
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
// Find "comparator":
|
||
$comparatorPatterns = array(
|
||
'<=', '>=', '<', '>', '=', '!=',
|
||
'NOT[[:space:]]+IN', 'IN',
|
||
'NOT[[:space:]]+LIKE[[:space:]]+BINARY', 'LIKE[[:space:]]+BINARY', 'NOT[[:space:]]+LIKE', 'LIKE',
|
||
'IS[[:space:]]+NOT', 'IS',
|
||
'BETWEEN', 'NOT[[:space]]+BETWEEN',
|
||
);
|
||
// Find "comparator":
|
||
$comparatorPatterns = array(
|
||
'<=', '>=', '<', '>', '=', '!=',
|
||
'NOT[[:space:]]+IN', 'IN',
|
||
'NOT[[:space:]]+LIKE[[:space:]]+BINARY', 'LIKE[[:space:]]+BINARY', 'NOT[[:space:]]+LIKE', 'LIKE',
|
||
'IS[[:space:]]+NOT', 'IS',
|
||
'BETWEEN', 'NOT[[:space]]+BETWEEN',
|
||
);
|
||
$stack[$level][$pnt[$level]]['comparator'] = $this->nextPart($parseString, '^(' . implode('|', $comparatorPatterns) . ')');
|
||
if (strlen($stack[$level][$pnt[$level]]['comparator'])) {
|
||
if (preg_match('/^CONCAT[[:space:]]*\(/', $parseString)) {
|
||
... | ... | |
// Look for ending parenthesis:
|
||
$this->nextPart($parseString, '([)])');
|
||
$stack[$level][$pnt[$level]]['value'] = $values;
|
||
} else if (t3lib_div::inList('IN,NOT IN', $stack[$level][$pnt[$level]]['comparator']) && preg_match('/^[(][[:space:]]*SELECT[[:space:]]+/', $parseString)) {
|
||
} else {
|
||
if (t3lib_div::inList('IN,NOT IN', $stack[$level][$pnt[$level]]['comparator']) && preg_match('/^[(][[:space:]]*SELECT[[:space:]]+/', $parseString)) {
|
||
$this->nextPart($parseString, '^([(])');
|
||
$stack[$level][$pnt[$level]]['subquery'] = $this->parseSELECT($parseString, $parameterReferences);
|
||
// Seek to new position in parseString after parsing of the subquery
|
||
$parseString = $stack[$level][$pnt[$level]]['subquery']['parseString'];
|
||
unset($stack[$level][$pnt[$level]]['subquery']['parseString']);
|
||
if (!$this->nextPart($parseString, '^([)])')) {
|
||
return 'No ) parenthesis at end of subquery';
|
||
}
|
||
$this->nextPart($parseString, '^([(])');
|
||
$stack[$level][$pnt[$level]]['subquery'] = $this->parseSELECT($parseString, $parameterReferences);
|
||
// Seek to new position in parseString after parsing of the subquery
|
||
$parseString = $stack[$level][$pnt[$level]]['subquery']['parseString'];
|
||
unset($stack[$level][$pnt[$level]]['subquery']['parseString']);
|
||
if (!$this->nextPart($parseString, '^([)])')) {
|
||
return 'No ) parenthesis at end of subquery';
|
||
}
|
||
} else if (t3lib_div::inList('BETWEEN,NOT BETWEEN', $stack[$level][$pnt[$level]]['comparator'])) {
|
||
} else {
|
||
if (t3lib_div::inList('BETWEEN,NOT BETWEEN', $stack[$level][$pnt[$level]]['comparator'])) {
|
||
$stack[$level][$pnt[$level]]['values'] = array();
|
||
$stack[$level][$pnt[$level]]['values'][0] = $this->getValue($parseString);
|
||
if (!$this->nextPart($parseString, '^(AND)')) {
|
||
return $this->parseError('No AND operator found as expected in parseWhereClause()', $parseString);
|
||
}
|
||
$stack[$level][$pnt[$level]]['values'][1] = $this->getValue($parseString);
|
||
} else {
|
||
// Finding value for comparator:
|
||
$stack[$level][$pnt[$level]]['value'] = &$this->getValueOrParameter($parseString, $stack[$level][$pnt[$level]]['comparator'], '', $parameterReferences);
|
||
$stack[$level][$pnt[$level]]['values'] = array();
|
||
$stack[$level][$pnt[$level]]['values'][0] = $this->getValue($parseString);
|
||
if (!$this->nextPart($parseString, '^(AND)')) {
|
||
return $this->parseError('No AND operator found as expected in parseWhereClause()', $parseString);
|
||
}
|
||
$stack[$level][$pnt[$level]]['values'][1] = $this->getValue($parseString);
|
||
} else {
|
||
// Finding value for comparator:
|
||
$stack[$level][$pnt[$level]]['value'] = &$this->getValueOrParameter($parseString, $stack[$level][$pnt[$level]]['comparator'], '', $parameterReferences);
|
||
if ($this->parse_error) {
|
||
if ($this->parse_error) {
|
||
return $this->parse_error;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
return $this->parse_error;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
// Finished, increase pointer:
|
||
$pnt[$level]++;
|
||
... | ... | |
}
|
||
// Checking if the current level is ended, in that case do stack management:
|
||
while ($this->nextPart($parseString,'^([)])')) {
|
||
while ($this->nextPart($parseString, '^([)])')) {
|
||
$level--; // Decrease level:
|
||
$level--; // Decrease level:
|
||
$stack[$level][$pnt[$level]]['sub'] = $stack[$level+1]; // Copy stack
|
||
$stack[$level][$pnt[$level]]['sub'] = $stack[$level + 1]; // Copy stack
|
||
$pnt[$level]++; // Increase pointer of the new level
|
||
$pnt[$level]++; // Increase pointer of the new level
|
||
// Make recursivity check:
|
||
$loopExit++;
|
||
... | ... | |
// Looking for stop-keywords:
|
||
if ($stopRegex && $this->lastStopKeyWord = $this->nextPart($parseString, $stopRegex)) {
|
||
$this->lastStopKeyWord = strtoupper(str_replace(array(' ',TAB,CR,LF), '', $this->lastStopKeyWord));
|
||
$this->lastStopKeyWord = strtoupper(str_replace(array(' ', TAB, CR, LF), '', $this->lastStopKeyWord));
|
||
return $stack[0];
|
||
} else {
|
||
return $this->parseError('No operator, but parsing not finished in parseWhereClause().', $parseString);
|
||
... | ... | |
$result = array();
|
||
// Field type:
|
||
if ($result['fieldType'] = $this->nextPart($parseString,'^(int|smallint|tinyint|mediumint|bigint|double|numeric|decimal|float|varchar|char|text|tinytext|mediumtext|longtext|blob|tinyblob|mediumblob|longblob)([[:space:],]+|\()')) {
|
||
if ($result['fieldType'] = $this->nextPart($parseString, '^(int|smallint|tinyint|mediumint|bigint|double|numeric|decimal|float|varchar|char|text|tinytext|mediumtext|longtext|blob|tinyblob|mediumblob|longblob)([[:space:],]+|\()')) {
|
||
// Looking for value:
|
||
if (substr($parseString,0,1)=='(') {
|
||
if (substr($parseString, 0, 1) == '(') {
|
||
$parseString = substr($parseString,1);
|
||
$parseString = substr($parseString, 1);
|
||
if ($result['value'] = $this->nextPart($parseString,'^([^)]*)')) {
|
||
if ($result['value'] = $this->nextPart($parseString, '^([^)]*)')) {
|
||
$parseString = ltrim(substr($parseString,1));
|
||
$parseString = ltrim(substr($parseString, 1));
|
||
} else return $this->parseError('No end-parenthesis for value found in parseFieldDef()!',$parseString);
|
||
} else {
|
||
return $this->parseError('No end-parenthesis for value found in parseFieldDef()!', $parseString);
|
||
}
|
||
}
|
||
}
|
||
// Looking for keywords
|
||
while($keyword = $this->nextPart($parseString,'^(DEFAULT|NOT[[:space:]]+NULL|AUTO_INCREMENT|UNSIGNED)([[:space:]]+|,|\))')) {
|
||
while ($keyword = $this->nextPart($parseString, '^(DEFAULT|NOT[[:space:]]+NULL|AUTO_INCREMENT|UNSIGNED)([[:space:]]+|,|\))')) {
|
||
$keywordCmp = strtoupper(str_replace(array(' ',TAB,CR,LF),'',$keyword));
|
||
$keywordCmp = strtoupper(str_replace(array(' ', TAB, CR, LF), '', $keyword));
|
||
$result['featureIndex'][$keywordCmp]['keyword'] = $keyword;
|
||
switch($keywordCmp) {
|
||
switch ($keywordCmp) {
|
||
case 'DEFAULT':
|
||
$result['featureIndex'][$keywordCmp]['value'] = $this->getValue($parseString);
|
||
break;
|
||
}
|
||
}
|
||
} else {
|
||
return $this->parseError('Field type unknown in parseFieldDef()!',$parseString);
|
||
return $this->parseError('Field type unknown in parseFieldDef()!', $parseString);
|
||
}
|
||
return $result;
|
||
}
|
||
/************************************
|
||
*
|
||
* Parsing: Helper functions
|
||
... | ... | |
*/
|
||
protected function nextPart(&$parseString, $regex, $trimAll = FALSE) {
|
||
$reg = array();
|
||
if (preg_match('/'.$regex.'/i',$parseString.' ', $reg)) { // Adding space char because [[:space:]]+ is often a requirement in regex's
|
||
if (preg_match('/' . $regex . '/i', $parseString . ' ', $reg)) { // Adding space char because [[:space:]]+ is often a requirement in regex's
|
||
$parseString = ltrim(substr($parseString,strlen($reg[$trimAll?0:1])));
|
||
$parseString = ltrim(substr($parseString, strlen($reg[$trimAll ? 0 : 1])));
|
||
return $reg[1];
|
||
}
|
||
// No match found
|
||
... | ... | |
}
|
||
$value = array('?');
|
||
$parameterReferences['?'][] = &$value;
|
||
} elseif ($parameter !== '') { // named parameter
|
||
} elseif ($parameter !== '') { // named parameter
|
||
if (isset($parameterReferences[$parameter])) {
|
||
// Use the same reference as last time we encountered this parameter
|
||
$value = &$parameterReferences[$parameter];
|
||
... | ... | |
protected function getValue(&$parseString, $comparator = '', $mode = '') {
|
||
$value = '';
|
||
if (t3lib_div::inList('NOTIN,IN,_LIST',strtoupper(str_replace(array(' ',LF,CR,TAB),'',$comparator)))) { // List of values:
|
||
if (t3lib_div::inList('NOTIN,IN,_LIST', strtoupper(str_replace(array(' ', LF, CR, TAB), '', $comparator)))) { // List of values:
|
||
if ($this->nextPart($parseString,'^([(])')) {
|
||
if ($this->nextPart($parseString, '^([(])')) {
|
||
$listValues = array();
|
||
$comma=',';
|
||
$comma = ',';
|
||
while($comma==',') {
|
||
while ($comma == ',') {
|
||
$listValues[] = $this->getValue($parseString);
|
||
if ($mode === 'INDEX') {
|
||
// Remove any length restriction on INDEX definition
|
||
$this->nextPart($parseString, '^([(]\d+[)])');
|
||
}
|
||
$comma = $this->nextPart($parseString,'^([,])');
|
||
$comma = $this->nextPart($parseString, '^([,])');
|
||
}
|
||
$out = $this->nextPart($parseString,'^([)])');
|
||
$out = $this->nextPart($parseString, '^([)])');
|
||
if ($out) {
|
||
if ($out) {
|
||
if ($comparator=='_LIST') {
|
||
if ($comparator == '_LIST') {
|
||
$kVals = array();
|
||
foreach ($listValues as $vArr) {
|
||
foreach ($listValues as $vArr) {
|
||
$kVals[] = $vArr[0];
|
||
}
|
||
return $kVals;
|
||
} else {
|
||
return $listValues;
|
||
}
|
||
} else return array($this->parseError('No ) parenthesis in list',$parseString));
|
||
} else return array($this->parseError('No ( parenthesis starting the list',$parseString));
|
||
} else {
|
||
return array($this->parseError('No ) parenthesis in list', $parseString));
|
||
}
|
||
} else {
|
||
return array($this->parseError('No ( parenthesis starting the list', $parseString));
|
||
}
|
||
} else { // Just plain string value, in quotes or not:
|
||
} else { // Just plain string value, in quotes or not:
|
||
// Quote?
|
||
$firstChar = substr($parseString,0,1);
|
||
$firstChar = substr($parseString, 0, 1);
|
||
switch($firstChar) {
|
||
switch ($firstChar) {
|
||
case '"':
|
||
$value = array($this->getValueInQuotes($parseString,'"'),'"');
|
||
$value = array($this->getValueInQuotes($parseString, '"'), '"');
|
||
break;
|
||
case "'":
|
||
$value = array($this->getValueInQuotes($parseString,"'"),"'");
|
||
$value = array($this->getValueInQuotes($parseString, "'"), "'");
|
||
break;
|
||
default:
|
||
$reg = array();
|
||
if (preg_match('/^([[:alnum:]._-]+)/i',$parseString, $reg)) {
|
||
if (preg_match('/^([[:alnum:]._-]+)/i', $parseString, $reg)) {
|
||
$parseString = ltrim(substr($parseString,strlen($reg[0])));
|
||
$parseString = ltrim(substr($parseString, strlen($reg[0])));
|
||
$value = array($reg[1]);
|
||
}
|
||
break;
|
||
... | ... | |
*/
|
||
protected function getValueInQuotes(&$parseString, $quote) {
|
||
$parts = explode($quote,substr($parseString,1));
|
||
$parts = explode($quote, substr($parseString, 1));
|
||
$buffer = '';
|
||
foreach($parts as $k => $v) {
|
||
foreach ($parts as $k => $v) {
|
||
$buffer.=$v;
|
||
$buffer .= $v;
|
||
$reg = array();
|
||
preg_match('/\\\\$/', $v, $reg);
|
||
if ($reg AND strlen($reg[0])%2) {
|
||
if ($reg AND strlen($reg[0]) % 2) {
|
||
$buffer.=$quote;
|
||
$buffer .= $quote;
|
||
} else {
|
||
$parseString = ltrim(substr($parseString,strlen($buffer)+2));
|
||
$parseString = ltrim(substr($parseString, strlen($buffer) + 2));
|
||
return $this->parseStripslashes($buffer);
|
||
}
|
||
}
|
||
... | ... | |
* @return string Error message.
|
||
*/
|
||
protected function parseError($msg, $restQuery) {
|
||
$this->parse_error = 'SQL engine parse ERROR: '.$msg.': near "'.substr($restQuery,0,50).'"';
|
||
$this->parse_error = 'SQL engine parse ERROR: ' . $msg . ': near "' . substr($restQuery, 0, 50) . '"';
|
||
return $this->parse_error;
|
||
}
|
||
... | ... | |
* @return string Output string
|
||
*/
|
||
protected function trimSQL($str) {
|
||
return trim(rtrim($str, "; \r\n\t")).' ';
|
||
return trim(rtrim($str, "; \r\n\t")) . ' ';
|
||
}
|
||
/*************************
|
||
*
|
||
* Compiling queries
|
||
... | ... | |
* @see parseSQL()
|
||
*/
|
||
public function compileSQL($components) {
|
||
switch($components['type']) {
|
||
switch ($components['type']) {
|
||
case 'SELECT':
|
||
$query = $this->compileSELECT($components);
|
||
break;
|
||
... | ... | |
$query = $this->compileDELETE($components);
|
||
break;
|
||
case 'EXPLAIN':
|
||
$query = 'EXPLAIN '.$this->compileSELECT($components);
|
||
$query = 'EXPLAIN ' . $this->compileSELECT($components);
|
||
break;
|
||
case 'DROPTABLE':
|
||
$query = 'DROP TABLE'.($components['ifExists']?' IF EXISTS':'').' '.$components['TABLE'];
|
||
$query = 'DROP TABLE' . ($components['ifExists'] ? ' IF EXISTS' : '') . ' ' . $components['TABLE'];
|
||
break;
|
||
case 'CREATETABLE':
|
||
$query = $this->compileCREATETABLE($components);
|
||
... | ... | |
$limit = $components['LIMIT'];
|
||