2 namespace TYPO3\CMS\Dbal\Database;
53 'NOT[[:space:]]+LIKE[[:space:]]+BINARY',
54 'LIKE[[:space:]]+BINARY',
55 'NOT[[:space:]]+LIKE',
60 'NOT[[:space]]+BETWEEN'
105 switch ((
string)$this->databaseConnection->handlerCfg[$this->databaseConnection->lastHandlerKey][
'type']) {
107 if ($this->databaseConnection->runningADOdbDriver(
'mssql')) {
129 $parts = explode($quote, substr($parseString, 1));
131 foreach ($parts as $k => $v) {
134 preg_match(
'/\\\\$/', $v, $reg);
135 if ($reg && strlen($reg[0]) % 2) {
138 $parseString = ltrim(substr($parseString, strlen($buffer) + 2));
153 $previousIsQuote =
false;
156 for ($c = 0; $c < strlen($parseString); $c++) {
158 if ($parseString[$c] === $quote) {
162 if ($previousIsQuote) {
167 $previousIsQuote = !$previousIsQuote;
172 }
elseif ($inQuote && $previousIsQuote) {
174 $previousIsQuote =
false;
176 $previousIsQuote =
false;
179 $parts = explode($quote, substr($parseString, 1));
181 foreach ($parts as $v) {
184 preg_match(
'/\\\\$/', $v, $reg);
185 if ($reg && strlen($reg[0]) % 2) {
188 $parseString = ltrim(substr($parseString, strlen($buffer) + 2));
211 $parseString = $this->
trimSQL($parseString);
212 $this->parse_error =
'';
215 $_parseString = $parseString;
217 $keyword = $this->
nextPart($_parseString,
'^(SELECT|UPDATE|INSERT[[:space:]]+INTO|DELETE[[:space:]]+FROM|EXPLAIN|(DROP|CREATE|ALTER|TRUNCATE)[[:space:]]+TABLE|CREATE[[:space:]]+DATABASE)[[:space:]]+');
252 case 'CREATEDATABASE':
256 case 'TRUNCATETABLE':
261 $result = $this->
parseError(
'"' . $keyword .
'" is not a keyword', $parseString);
274 protected function parseSELECT($parseString, &$parameterReferences = null)
277 $parseString = $this->
trimSQL($parseString);
278 $parseString = ltrim(substr($parseString, 6));
281 if ($parameterReferences === null) {
282 $result[
'parameters'] = array();
283 $parameterReferences = &$result[
'parameters'];
285 $result[
'type'] =
'SELECT';
287 $result[
'STRAIGHT_JOIN'] = $this->
nextPart($parseString,
'^(STRAIGHT_JOIN)[[:space:]]+');
289 $result[
'SELECT'] = $this->
parseFieldList($parseString,
'^(FROM)[[:space:]]+');
290 if ($this->parse_error) {
296 $result[
'FROM'] = $this->
parseFromTables($parseString,
'^(WHERE)[[:space:]]+');
297 if ($this->parse_error) {
303 $result[
'WHERE'] = $this->
parseWhereClause($parseString,
'^((GROUP|ORDER)[[:space:]]+BY|LIMIT)[[:space:]]+', $parameterReferences);
304 if ($this->parse_error) {
308 if ($this->lastStopKeyWord) {
310 if ($this->lastStopKeyWord ===
'GROUPBY') {
311 $result[
'GROUPBY'] = $this->
parseFieldList($parseString,
'^(ORDER[[:space:]]+BY|LIMIT)[[:space:]]+');
312 if ($this->parse_error) {
317 if ($this->lastStopKeyWord ===
'ORDERBY') {
318 $result[
'ORDERBY'] = $this->
parseFieldList($parseString,
'^(LIMIT)[[:space:]]+');
319 if ($this->parse_error) {
324 if ($this->lastStopKeyWord ===
'LIMIT') {
325 if (preg_match(
'/^([0-9]+|[0-9]+[[:space:]]*,[[:space:]]*[0-9]+)$/', trim($parseString))) {
326 $result[
'LIMIT'] = $parseString;
328 return $this->
parseError(
'No value for limit!', $parseString);
334 return $this->
parseError(
'No table to select from!', $parseString);
337 $result[
'parseString'] = $parseString;
352 $parseString = $this->
trimSQL($parseString);
353 $parseString = ltrim(substr($parseString, 6));
356 $result[
'type'] =
'UPDATE';
358 $result[
'TABLE'] = $this->
nextPart($parseString,
'^([[:alnum:]_]+)[[:space:]]+');
360 if ($result[
'TABLE']) {
361 if ($parseString && $this->
nextPart($parseString,
'^(SET)[[:space:]]+')) {
365 if ($fieldName = $this->
nextPart($parseString,
'^([[:alnum:]_]+)[[:space:]]*=')) {
367 $this->
nextPart($parseString,
'^(=)');
368 $value = $this->
getValue($parseString);
369 $result[
'FIELDS'][$fieldName] = $value;
371 return $this->
parseError(
'No fieldname found', $parseString);
373 $comma = $this->
nextPart($parseString,
'^(,)');
376 if ($this->
nextPart($parseString,
'^(WHERE)')) {
378 if ($this->parse_error) {
383 return $this->
parseError(
'Query missing SET...', $parseString);
386 return $this->
parseError(
'No table found!', $parseString);
390 return $this->
parseError(
'Still content in clause after parsing!', $parseString);
406 $parseString = $this->
trimSQL($parseString);
407 $parseString = ltrim(substr(ltrim(substr($parseString, 6)), 4));
410 $result[
'type'] =
'INSERT';
412 $result[
'TABLE'] = $this->
nextPart($parseString,
'^([[:alnum:]_]+)([[:space:]]+|\\()');
413 if ($result[
'TABLE']) {
415 if ($this->
nextPart($parseString,
'^(VALUES)([[:space:]]+|\\()')) {
417 $result[
'VALUES_ONLY'] = $this->
getValue($parseString,
'IN');
418 if ($this->parse_error) {
421 if (preg_match(
'/^,/', $parseString)) {
422 $result[
'VALUES_ONLY'] = array($result[
'VALUES_ONLY']);
423 $result[
'EXTENDED'] =
'1';
424 while ($this->
nextPart($parseString,
'^(,)') ===
',') {
425 $result[
'VALUES_ONLY'][] = $this->
getValue($parseString,
'IN');
426 if ($this->parse_error) {
433 $fieldNames = $this->
getValue($parseString,
'_LIST');
434 if ($this->parse_error) {
438 if ($this->
nextPart($parseString,
'^(VALUES)([[:space:]]+|\\()')) {
439 $result[
'FIELDS'] = array();
442 $values = $this->
getValue($parseString,
'IN');
443 if ($this->parse_error) {
446 $insertValues = array();
447 foreach ($fieldNames as $k => $fN) {
448 if (preg_match(
'/^[[:alnum:]_]+$/', $fN)) {
449 if (isset($values[$k])) {
450 if (!isset($insertValues[$fN])) {
451 $insertValues[$fN] = $values[$k];
453 return $this->
parseError(
'Fieldname ("' . $fN .
'") already found in list!', $parseString);
456 return $this->
parseError(
'No value set!', $parseString);
459 return $this->
parseError(
'Invalid fieldname ("' . $fN .
'")', $parseString);
462 if (isset($values[$k + 1])) {
463 return $this->
parseError(
'Too many values in list!', $parseString);
465 $result[
'FIELDS'][] = $insertValues;
466 }
while ($this->
nextPart($parseString,
'^(,)') ===
',');
467 if (count($result[
'FIELDS']) === 1) {
468 $result[
'FIELDS'] = $result[
'FIELDS'][0];
470 $result[
'EXTENDED'] =
'1';
473 return $this->
parseError(
'VALUES keyword expected', $parseString);
477 return $this->
parseError(
'No table found!', $parseString);
481 return $this->
parseError(
'Still content after parsing!', $parseString);
497 $parseString = $this->
trimSQL($parseString);
498 $parseString = ltrim(substr(ltrim(substr($parseString, 6)), 4));
501 $result[
'type'] =
'DELETE';
503 $result[
'TABLE'] = $this->
nextPart($parseString,
'^([[:alnum:]_]+)[[:space:]]+');
504 if ($result[
'TABLE']) {
506 if ($this->
nextPart($parseString,
'^(WHERE)')) {
508 if ($this->parse_error) {
513 return $this->
parseError(
'No table found!', $parseString);
517 return $this->
parseError(
'Still content in clause after parsing!', $parseString);
533 $parseString = $this->
trimSQL($parseString);
534 $parseString = ltrim(substr($parseString, 6));
537 if (is_array($result)) {
538 $result[
'type'] =
'EXPLAIN';
553 $parseString = $this->
trimSQL($parseString);
554 $parseString = ltrim(substr(ltrim(substr($parseString, 6)), 5));
557 $result[
'type'] =
'CREATETABLE';
559 $result[
'TABLE'] = $this->
nextPart($parseString,
'^([[:alnum:]_]+)[[:space:]]*\\(',
true);
560 if ($result[
'TABLE']) {
562 while ($parseString !==
'') {
564 if ($key = $this->
nextPart($parseString,
'^(KEY|PRIMARY KEY|UNIQUE KEY|UNIQUE)([[:space:]]+|\\()')) {
568 $result[
'KEYS'][
'PRIMARYKEY'] = $this->
getValue($parseString,
'_LIST');
569 if ($this->parse_error) {
576 if ($keyName = $this->
nextPart($parseString,
'^([[:alnum:]_]+)([[:space:]]+|\\()')) {
577 $result[
'KEYS'][
'UNIQUE'] = array($keyName => $this->
getValue($parseString,
'_LIST'));
578 if ($this->parse_error) {
582 return $this->
parseError(
'No keyname found', $parseString);
586 if ($keyName = $this->
nextPart($parseString,
'^([[:alnum:]_]+)([[:space:]]+|\\()')) {
587 $result[
'KEYS'][$keyName] = $this->
getValue($parseString,
'_LIST',
'INDEX');
588 if ($this->parse_error) {
592 return $this->
parseError(
'No keyname found', $parseString);
596 }
elseif ($fieldName = $this->
nextPart($parseString,
'^([[:alnum:]_]+)[[:space:]]+')) {
598 $result[
'FIELDS'][$fieldName][
'definition'] = $this->
parseFieldDef($parseString);
599 if ($this->parse_error) {
604 $delim = $this->
nextPart($parseString,
'^(,|\\))');
606 return $this->
parseError(
'No delimiter found', $parseString);
607 }
elseif ($delim ===
')') {
612 if ($delim ===
')') {
613 if ($this->
nextPart($parseString,
'^((ENGINE|TYPE)[[:space:]]*=)')) {
614 $result[
'engine'] = $parseString;
618 return $this->
parseError(
'No fieldname found!', $parseString);
621 return $this->
parseError(
'No table found!', $parseString);
625 return $this->
parseError(
'Still content in clause after parsing!', $parseString);
640 $parseString = $this->
trimSQL($parseString);
641 $parseString = ltrim(substr(ltrim(substr($parseString, 5)), 5));
644 $result[
'type'] =
'ALTERTABLE';
646 $hasBackquote = $this->
nextPart($parseString,
'^(`)') ===
'`';
647 $result[
'TABLE'] = $this->
nextPart($parseString,
'^([[:alnum:]_]+)' . ($hasBackquote ?
'`' :
'') .
'[[:space:]]+');
648 if ($hasBackquote && $this->
nextPart($parseString,
'^(`)') !==
'`') {
649 return $this->
parseError(
'No end backquote found!', $parseString);
651 if ($result[
'TABLE']) {
652 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:]]+|\\(|=)')) {
655 if (
GeneralUtility::inList(
'ADDPRIMARYKEY,DROPPRIMARYKEY,ENGINE', $actionKey) || ($fieldKey = $this->
nextPart($parseString,
'^([[:alnum:]_]+)[[:space:]]+'))) {
656 switch ($actionKey) {
658 $result[
'FIELD'] = $fieldKey;
660 if ($this->parse_error) {
666 $result[
'FIELD'] = $fieldKey;
669 $result[
'FIELD'] = $fieldKey;
670 if ($result[
'newField'] = $this->
nextPart($parseString,
'^([[:alnum:]_]+)[[:space:]]+')) {
672 if ($this->parse_error) {
676 return $this->
parseError(
'No NEW field name found', $parseString);
680 case 'ADDPRIMARYKEY':
682 $result[
'KEY'] = $fieldKey;
683 $result[
'fields'] = $this->
getValue($parseString,
'_LIST',
'INDEX');
684 if ($this->parse_error) {
689 $result[
'KEY'] = $fieldKey;
691 case 'DROPPRIMARYKEY':
694 case 'DEFAULTCHARACTERSET':
695 $result[
'charset'] = $fieldKey;
698 $result[
'engine'] = $this->
nextPart($parseString,
'^=[[:space:]]*([[:alnum:]]+)[[:space:]]+',
true);
702 return $this->
parseError(
'No field name found', $parseString);
705 return $this->
parseError(
'No action CHANGE, DROP or ADD found!', $parseString);
708 return $this->
parseError(
'No table found!', $parseString);
712 return $this->
parseError(
'Still content in clause after parsing!', $parseString);
726 $parseString = $this->
trimSQL($parseString);
727 $parseString = ltrim(substr(ltrim(substr($parseString, 4)), 5));
730 $result[
'type'] =
'DROPTABLE';
732 $result[
'ifExists'] = $this->
nextPart($parseString,
'^(IF[[:space:]]+EXISTS[[:space:]]+)');
734 $result[
'TABLE'] = $this->
nextPart($parseString,
'^([[:alnum:]_]+)[[:space:]]+');
735 if ($result[
'TABLE']) {
738 return $this->
parseError(
'Still content in clause after parsing!', $parseString);
742 return $this->
parseError(
'No table found!', $parseString);
755 $parseString = $this->
trimSQL($parseString);
756 $parseString = ltrim(substr(ltrim(substr($parseString, 6)), 8));
759 $result[
'type'] =
'CREATEDATABASE';
761 $result[
'DATABASE'] = $this->
nextPart($parseString,
'^([[:alnum:]_]+)[[:space:]]+');
762 if ($result[
'DATABASE']) {
765 return $this->
parseError(
'Still content in clause after parsing!', $parseString);
769 return $this->
parseError(
'No database found!', $parseString);
782 $parseString = $this->
trimSQL($parseString);
783 $parseString = ltrim(substr(ltrim(substr($parseString, 8)), 5));
786 $result[
'type'] =
'TRUNCATETABLE';
788 $result[
'TABLE'] = $this->
nextPart($parseString,
'^([[:alnum:]_]+)[[:space:]]+');
789 if ($result[
'TABLE']) {
792 return $this->
parseError(
'Still content in clause after parsing!', $parseString);
796 return $this->
parseError(
'No table found!', $parseString);
819 if ($parseString ===
'') {
830 $parseString = $this->
trimSQL($parseString);
831 $this->lastStopKeyWord =
'';
832 $this->parse_error =
'';
834 $stack[$pnt][
'comments'] = $this->
nextPart($parseString,
'^(\\/\\*.*\\*\\/)');
836 while ($parseString !==
'') {
841 $funcContent = $this->
nextPart($parseString,
'^([^()]*.)');
842 $stack[$pnt][
'func_content.'][] = array(
844 'func_content' => substr($funcContent, 0, -1)
846 $stack[$pnt][
'func_content'] .= $funcContent;
848 switch (substr($stack[$pnt][
'func_content'], -1)) {
856 $stack[$pnt][
'func_content'] = substr($stack[$pnt][
'func_content'], 0, -1);
858 $parseString = ltrim($parseString);
865 if (preg_match(
'/^case([[:space:]][[:alnum:]\\*._]+)?[[:space:]]when/i', $parseString)) {
866 $stack[$pnt][
'type'] =
'flow-control';
869 if ($as = $this->
nextPart($parseString,
'^(AS)[[:space:]]+')) {
870 $stack[$pnt][
'as'] = $this->
nextPart($parseString,
'^([[:alnum:]_]+)(,|[[:space:]]+)');
871 $stack[$pnt][
'as_keyword'] = $as;
875 $func = $this->
nextPart($parseString,
'^(count|max|min|floor|sum|avg)[[:space:]]*\\(');
878 $parseString = trim(substr($parseString, 1));
879 $stack[$pnt][
'type'] =
'function';
880 $stack[$pnt][
'function'] = $func;
884 $stack[$pnt][
'distinct'] = $this->
nextPart($parseString,
'^(distinct[[:space:]]+)');
886 if (($fieldName = $this->
nextPart($parseString,
'^([[:alnum:]\\*._]+)(,|[[:space:]]+)')) !==
'') {
887 $stack[$pnt][
'type'] =
'field';
889 $tableField = explode(
'.', $fieldName, 2);
890 if (count($tableField) === 2) {
891 $stack[$pnt][
'table'] = $tableField[0];
892 $stack[$pnt][
'field'] = $tableField[1];
894 $stack[$pnt][
'table'] =
'';
895 $stack[$pnt][
'field'] = $tableField[0];
898 return $this->
parseError(
'No field name found as expected in parseFieldList()', $parseString);
906 if ($as = $this->
nextPart($parseString,
'^(AS)[[:space:]]+')) {
907 $stack[$pnt][
'as'] = $this->
nextPart($parseString,
'^([[:alnum:]_]+)(,|[[:space:]]+)');
908 $stack[$pnt][
'as_keyword'] = $as;
911 if ($sDir = $this->
nextPart($parseString,
'^(ASC|DESC)([[:space:]]+|,)')) {
912 $stack[$pnt][
'sortDir'] = $sDir;
915 if ($stopRegex && ($this->lastStopKeyWord = $this->
nextPart($parseString, $stopRegex))) {
920 if ($parseString !==
'' && !$this->
nextPart($parseString,
'^(,)')) {
921 return $this->
parseError(
'No comma found as expected in parseFieldList()', $parseString);
928 if ($loopExit > 500) {
929 return $this->
parseError(
'More than 500 loops, exiting prematurely in parseFieldList()...', $parseString);
947 $result[
'type'] = $this->
nextPart($parseString,
'^(case)[[:space:]]+');
948 if (!preg_match(
'/^when[[:space:]]+/i', $parseString)) {
949 $value = $this->
getValue($parseString);
950 if (!(isset($value[1]) || is_numeric($value[0]))) {
951 $result[
'case_field'] = $value[0];
953 $result[
'case_value'] = $value;
956 $result[
'when'] = array();
957 while ($this->
nextPart($parseString,
'^(when)[[:space:]]')) {
959 $when[
'when_value'] = $this->
parseWhereClause($parseString,
'^(then)[[:space:]]+');
960 $when[
'then_value'] = $this->
getValue($parseString);
961 $result[
'when'][] = $when;
963 if ($this->
nextPart($parseString,
'^(else)[[:space:]]+')) {
964 $result[
'else'] = $this->
getValue($parseString);
966 if (!$this->
nextPart($parseString,
'^(end)[[:space:]]+')) {
967 return $this->
parseError(
'No "end" keyword found as expected in parseCaseStatement()', $parseString);
981 $this->
nextPart($parseString,
'^(CAST)[[:space:]]*');
982 $parseString = trim(substr($parseString, 1));
983 $castDefinition = array(
'type' =>
'cast');
985 if ($fieldName = $this->
nextPart($parseString,
'^([[:alnum:]\\*._]+)[[:space:]]*')) {
987 $tableField = explode(
'.', $fieldName, 2);
988 if (count($tableField) === 2) {
989 $castDefinition[
'table'] = $tableField[0];
990 $castDefinition[
'field'] = $tableField[1];
992 $castDefinition[
'table'] =
'';
993 $castDefinition[
'field'] = $tableField[0];
996 return $this->
parseError(
'No casted join field found in parseCastStatement()!', $parseString);
998 if ($this->
nextPart($parseString,
'^([[:space:]]*AS[[:space:]]*)')) {
999 $castDefinition[
'datatype'] = $this->
getValue($parseString);
1001 if (!$this->
nextPart($parseString,
'^([)])')) {
1002 return $this->
parseError(
'No end parenthesis at end of CAST function', $parseString);
1004 return $castDefinition;
1019 $parseString = $this->
trimSQL($parseString);
1020 $this->lastStopKeyWord =
'';
1021 $this->parse_error =
'';
1029 while ($parseString !==
'') {
1031 if ($stack[$pnt][
'table'] = $this->
nextPart($parseString,
'^([[:alnum:]_]+)(,|[[:space:]]+)')) {
1033 if ($stopRegex && ($this->lastStopKeyWord = $this->
nextPart($parseString, $stopRegex))) {
1037 if (!preg_match(
'/^(LEFT|RIGHT|JOIN|INNER)[[:space:]]+/i', $parseString)) {
1038 $stack[$pnt][
'as_keyword'] = $this->
nextPart($parseString,
'^(AS[[:space:]]+)');
1039 $stack[$pnt][
'as'] = $this->
nextPart($parseString,
'^([[:alnum:]_]+)[[:space:]]*');
1042 return $this->
parseError(
'No table name found as expected in parseFromTables()!', $parseString);
1046 while ($join = $this->
nextPart($parseString,
'^(((INNER|(LEFT|RIGHT)([[:space:]]+OUTER)?)[[:space:]]+)?JOIN)[[:space:]]+')) {
1047 $stack[$pnt][
'JOIN'][$joinCnt][
'type'] = $join;
1048 if ($stack[$pnt][
'JOIN'][$joinCnt][
'withTable'] = $this->
nextPart($parseString,
'^([[:alnum:]_]+)[[:space:]]+', 1)) {
1049 if (!preg_match(
'/^ON[[:space:]]+/i', $parseString)) {
1050 $stack[$pnt][
'JOIN'][$joinCnt][
'as_keyword'] = $this->
nextPart($parseString,
'^(AS[[:space:]]+)');
1051 $stack[$pnt][
'JOIN'][$joinCnt][
'as'] = $this->
nextPart($parseString,
'^([[:alnum:]_]+)[[:space:]]+');
1053 if (!$this->
nextPart($parseString,
'^(ON[[:space:]]+)')) {
1054 return $this->
parseError(
'No join condition found in parseFromTables()!', $parseString);
1056 $stack[$pnt][
'JOIN'][$joinCnt][
'ON'] = array();
1057 $condition = array(
'operator' =>
'');
1058 $parseCondition =
true;
1059 while ($parseCondition) {
1060 if (($fieldName = $this->
nextPart($parseString,
'^([[:alnum:]._]+)[[:space:]]*(<=|>=|<|>|=|!=)')) !==
'') {
1062 $tableField = explode(
'.', $fieldName, 2);
1063 $condition[
'left'] = array();
1064 if (count($tableField) === 2) {
1065 $condition[
'left'][
'table'] = $tableField[0];
1066 $condition[
'left'][
'field'] = $tableField[1];
1068 $condition[
'left'][
'table'] =
'';
1069 $condition[
'left'][
'field'] = $tableField[0];
1071 }
elseif (preg_match(
'/^CAST[[:space:]]*[(]/i', $parseString)) {
1074 if (!is_array($condition[
'left'])) {
1075 return $condition[
'left'];
1078 return $this->
parseError(
'No join field found in parseFromTables()!', $parseString);
1081 $condition[
'comparator'] = $this->
nextPart($parseString,
'^(<=|>=|<|>|=|!=)');
1082 if (preg_match(
'/^CAST[[:space:]]*[(]/i', $parseString)) {
1085 if (!is_array($condition[
'right'])) {
1086 return $condition[
'right'];
1088 }
elseif (($fieldName = $this->
nextPart($parseString,
'^([[:alnum:]._]+)')) !==
'') {
1090 $tableField = explode(
'.', $fieldName, 2);
1091 $condition[
'right'] = array();
1092 if (count($tableField) === 2) {
1093 $condition[
'right'][
'table'] = $tableField[0];
1094 $condition[
'right'][
'field'] = $tableField[1];
1096 $condition[
'right'][
'table'] =
'';
1097 $condition[
'right'][
'field'] = $tableField[0];
1100 $condition[
'right'][
'value'] = $value;
1102 return $this->
parseError(
'No join field found in parseFromTables()!', $parseString);
1104 $stack[$pnt][
'JOIN'][$joinCnt][
'ON'][] = $condition;
1105 if (($operator = $this->
nextPart($parseString,
'^(AND|OR)')) !==
'') {
1106 $condition = array(
'operator' => $operator);
1108 $parseCondition =
false;
1113 return $this->
parseError(
'No join table found in parseFromTables()!', $parseString);
1117 if ($stopRegex && ($this->lastStopKeyWord = $this->
nextPart($parseString, $stopRegex))) {
1122 if ($parseString !==
'' && !$this->
nextPart($parseString,
'^(,)')) {
1123 return $this->
parseError(
'No comma found as expected in parseFromTables()', $parseString);
1129 if ($loopExit > 500) {
1130 return $this->
parseError(
'More than 500 loops, exiting prematurely in parseFromTables()...', $parseString);
1146 public function parseWhereClause(&$parseString, $stopRegex =
'', array &$parameterReferences = array())
1149 $parseString = $this->
trimSQL($parseString);
1150 $this->lastStopKeyWord =
'';
1151 $this->parse_error =
'';
1153 $stack = array(0 => array());
1155 $pnt = array(0 => 0);
1161 while ($parseString !==
'') {
1163 $newLevel = $this->
nextPart($parseString,
'^([(])');
1165 if ($newLevel ===
'(') {
1171 $stack[$level] = array();
1175 $stack[$level][$pnt[$level]][
'modifier'] = trim($this->
nextPart($parseString,
'^(!|NOT[[:space:]]+)'));
1177 if (preg_match(
'/^EXISTS[[:space:]]*[(]/i', $parseString)) {
1178 $stack[$level][$pnt[$level]][
'func'][
'type'] = $this->
nextPart($parseString,
'^(EXISTS)[[:space:]]*');
1180 $parseString = trim(substr($parseString, 1));
1181 $stack[$level][$pnt[$level]][
'func'][
'subquery'] = $this->
parseSELECT($parseString, $parameterReferences);
1183 $parseString = $stack[$level][$pnt[$level]][
'func'][
'subquery'][
'parseString'];
1184 unset($stack[$level][$pnt[$level]][
'func'][
'subquery'][
'parseString']);
1185 if (!$this->
nextPart($parseString,
'^([)])')) {
1186 return 'No ) parenthesis at end of subquery';
1190 if (preg_match(
'/^LOCATE[[:space:]]*[(]/i', $parseString)) {
1191 $stack[$level][$pnt[$level]][
'func'][
'type'] = $this->
nextPart($parseString,
'^(LOCATE)[[:space:]]*');
1193 $parseString = trim(substr($parseString, 1));
1194 $stack[$level][$pnt[$level]][
'func'][
'substr'] = $this->
getValue($parseString);
1195 if (!$this->
nextPart($parseString,
'^(,)')) {
1196 return $this->
parseError(
'No comma found as expected in parseWhereClause()', $parseString);
1198 if ($fieldName = $this->
nextPart($parseString,
'^([[:alnum:]\\*._]+)[[:space:]]*')) {
1200 $tableField = explode(
'.', $fieldName, 2);
1201 if (count($tableField) === 2) {
1202 $stack[$level][$pnt[$level]][
'func'][
'table'] = $tableField[0];
1203 $stack[$level][$pnt[$level]][
'func'][
'field'] = $tableField[1];
1205 $stack[$level][$pnt[$level]][
'func'][
'table'] =
'';
1206 $stack[$level][$pnt[$level]][
'func'][
'field'] = $tableField[0];
1209 return $this->
parseError(
'No field name found as expected in parseWhereClause()', $parseString);
1211 if ($this->
nextPart($parseString,
'^(,)')) {
1212 $stack[$level][$pnt[$level]][
'func'][
'pos'] = $this->
getValue($parseString);
1214 if (!$this->
nextPart($parseString,
'^([)])')) {
1215 return $this->
parseError(
'No ) parenthesis at end of function', $parseString);
1217 }
elseif (preg_match(
'/^IFNULL[[:space:]]*[(]/i', $parseString)) {
1218 $stack[$level][$pnt[$level]][
'func'][
'type'] = $this->
nextPart($parseString,
'^(IFNULL)[[:space:]]*');
1219 $parseString = trim(substr($parseString, 1));
1221 if ($fieldName = $this->
nextPart($parseString,
'^([[:alnum:]\\*._]+)[[:space:]]*')) {
1223 $tableField = explode(
'.', $fieldName, 2);
1224 if (count($tableField) === 2) {
1225 $stack[$level][$pnt[$level]][
'func'][
'table'] = $tableField[0];
1226 $stack[$level][$pnt[$level]][
'func'][
'field'] = $tableField[1];
1228 $stack[$level][$pnt[$level]][
'func'][
'table'] =
'';
1229 $stack[$level][$pnt[$level]][
'func'][
'field'] = $tableField[0];
1232 return $this->
parseError(
'No field name found as expected in parseWhereClause()', $parseString);
1234 if ($this->
nextPart($parseString,
'^(,)')) {
1235 $stack[$level][$pnt[$level]][
'func'][
'default'] = $this->
getValue($parseString);
1237 if (!$this->
nextPart($parseString,
'^([)])')) {
1238 return $this->
parseError(
'No ) parenthesis at end of function', $parseString);
1240 }
elseif (preg_match(
'/^CAST[[:space:]]*[(]/i', $parseString)) {
1241 $stack[$level][$pnt[$level]][
'func'][
'type'] = $this->
nextPart($parseString,
'^(CAST)[[:space:]]*');
1242 $parseString = trim(substr($parseString, 1));
1244 if ($fieldName = $this->
nextPart($parseString,
'^([[:alnum:]\\*._]+)[[:space:]]*')) {
1246 $tableField = explode(
'.', $fieldName, 2);
1247 if (count($tableField) === 2) {
1248 $stack[$level][$pnt[$level]][
'func'][
'table'] = $tableField[0];
1249 $stack[$level][$pnt[$level]][
'func'][
'field'] = $tableField[1];
1251 $stack[$level][$pnt[$level]][
'func'][
'table'] =
'';
1252 $stack[$level][$pnt[$level]][
'func'][
'field'] = $tableField[0];
1255 return $this->
parseError(
'No field name found as expected in parseWhereClause()', $parseString);
1257 if ($this->
nextPart($parseString,
'^([[:space:]]*AS[[:space:]]*)')) {
1258 $stack[$level][$pnt[$level]][
'func'][
'datatype'] = $this->
getValue($parseString);
1260 if (!$this->
nextPart($parseString,
'^([)])')) {
1261 return $this->
parseError(
'No ) parenthesis at end of function', $parseString);
1263 }
elseif (preg_match(
'/^FIND_IN_SET[[:space:]]*[(]/i', $parseString)) {
1264 $stack[$level][$pnt[$level]][
'func'][
'type'] = $this->
nextPart($parseString,
'^(FIND_IN_SET)[[:space:]]*');
1266 $parseString = trim(substr($parseString, 1));
1267 if ($str = $this->
getValue($parseString)) {
1268 $stack[$level][$pnt[$level]][
'func'][
'str'] = $str;
1269 if ($fieldName = $this->
nextPart($parseString,
'^,[[:space:]]*([[:alnum:]._]+)[[:space:]]*',
true)) {
1271 $tableField = explode(
'.', $fieldName, 2);
1272 if (count($tableField) === 2) {
1273 $stack[$level][$pnt[$level]][
'func'][
'table'] = $tableField[0];
1274 $stack[$level][$pnt[$level]][
'func'][
'field'] = $tableField[1];
1276 $stack[$level][$pnt[$level]][
'func'][
'table'] =
'';
1277 $stack[$level][$pnt[$level]][
'func'][
'field'] = $tableField[0];
1280 return $this->
parseError(
'No field name found as expected in parseWhereClause()', $parseString);
1282 if (!$this->
nextPart($parseString,
'^([)])')) {
1283 return $this->
parseError(
'No ) parenthesis at end of function', $parseString);
1286 return $this->
parseError(
'No item to look for found as expected in parseWhereClause()', $parseString);
1296 $calcOperators =
'&|\\+|-|\\*|\\/|%';
1298 if (($fieldName = $this->
nextPart($parseString,
'^([[:alnum:]._]+)([[:space:]]+|' . $calcOperators .
'|<=|>=|<|>|=|!=|IS)')) !==
'') {
1300 $tableField = explode(
'.', $fieldName, 2);
1301 if (count($tableField) === 2) {
1302 $stack[$level][$pnt[$level]][
'table'] = $tableField[0];
1303 $stack[$level][$pnt[$level]][
'field'] = $tableField[1];
1305 $stack[$level][$pnt[$level]][
'table'] =
'';
1306 $stack[$level][$pnt[$level]][
'field'] = $tableField[0];
1309 return $this->
parseError(
'No field name found as expected in parseWhereClause()', $parseString);
1312 $stack[$level][$pnt[$level]][
'calc'] = $this->
nextPart($parseString,
'^(' . $calcOperators .
')');
1313 if ((
string)$stack[$level][$pnt[$level]][
'calc'] !==
'') {
1315 $calc_value = $this->
getValue($parseString);
1316 $stack[$level][$pnt[$level]][
'calc_value'] = $calc_value;
1317 if (count($calc_value) === 1 && is_string($calc_value[0])) {
1319 $tableField = explode(
'.', $calc_value[0], 2);
1320 if (count($tableField) === 2) {
1321 $stack[$level][$pnt[$level]][
'calc_table'] = $tableField[0];
1322 $stack[$level][$pnt[$level]][
'calc_field'] = $tableField[1];
1324 $stack[$level][$pnt[$level]][
'calc_table'] =
'';
1325 $stack[$level][$pnt[$level]][
'calc_field'] = $tableField[0];
1330 $stack[$level][$pnt[$level]][
'comparator'] = $this->
nextPart($parseString,
'^(' . implode(
'|', self::$comparatorPatterns) .
')');
1331 if ($stack[$level][$pnt[$level]][
'comparator'] !==
'') {
1332 if (preg_match(
'/^CONCAT[[:space:]]*\\(/', $parseString)) {
1333 $this->
nextPart($parseString,
'^(CONCAT[[:space:]]?[(])');
1335 'operator' =>
'CONCAT',
1339 while ($fieldName = $this->
nextPart($parseString,
'^([[:alnum:]._]+)')) {
1341 $tableField = explode(
'.', $fieldName, 2);
1342 if (count($tableField) === 2) {
1343 $values[
'args'][$cnt][
'table'] = $tableField[0];
1344 $values[
'args'][$cnt][
'field'] = $tableField[1];
1346 $values[
'args'][$cnt][
'table'] =
'';
1347 $values[
'args'][$cnt][
'field'] = $tableField[0];
1350 $this->
nextPart($parseString,
'^(,)');
1354 $this->
nextPart($parseString,
'([)])');
1355 $stack[$level][$pnt[$level]][
'value'] = $values;
1357 if (
GeneralUtility::inList(
'IN,NOT IN', $stack[$level][$pnt[$level]][
'comparator']) && preg_match(
'/^[(][[:space:]]*SELECT[[:space:]]+/', $parseString)) {
1358 $this->
nextPart($parseString,
'^([(])');
1359 $stack[$level][$pnt[$level]][
'subquery'] = $this->
parseSELECT($parseString, $parameterReferences);
1361 if (!empty($stack[$level][$pnt[$level]][
'subquery'][
'parseString'])) {
1362 $parseString = $stack[$level][$pnt[$level]][
'subquery'][
'parseString'];
1363 unset($stack[$level][$pnt[$level]][
'subquery'][
'parseString']);
1365 if (!$this->
nextPart($parseString,
'^([)])')) {
1366 return 'No ) parenthesis at end of subquery';
1370 $stack[$level][$pnt[$level]][
'values'] = array();
1371 $stack[$level][$pnt[$level]][
'values'][0] = $this->
getValue($parseString);
1372 if (!$this->
nextPart($parseString,
'^(AND)')) {
1373 return $this->
parseError(
'No AND operator found as expected in parseWhereClause()', $parseString);
1375 $stack[$level][$pnt[$level]][
'values'][1] = $this->
getValue($parseString);
1378 $stack[$level][$pnt[$level]][
'value'] = &$this->
getValueOrParameter($parseString, $stack[$level][$pnt[$level]][
'comparator'],
'', $parameterReferences);
1379 if ($this->parse_error) {
1391 if ($level === 0 && preg_match(
'/^[)]/', $parseString)) {
1397 if ($level === 0 && preg_match(
'/^[)]/', $parseString)) {
1402 while ($this->
nextPart($parseString,
'^([)])')) {
1406 $stack[$level][$pnt[$level]][
'sub'] = $stack[$level + 1];
1411 if ($loopExit > 500) {
1412 return $this->
parseError(
'More than 500 loops (in search for exit parenthesis), exiting prematurely in parseWhereClause()...', $parseString);
1416 $op = $this->
nextPart($parseString,
'^(AND[[:space:]]+NOT|&&[[:space:]]+NOT|OR[[:space:]]+NOT|OR[[:space:]]+NOT|\\|\\|[[:space:]]+NOT|AND|&&|OR|\\|\\|)(\\(|[[:space:]]+)');
1419 $op = str_replace(array(
'&&',
'||'), array(
'AND',
'OR'), $op);
1420 $stack[$level][$pnt[$level]][
'operator'] = $op;
1421 }
elseif ($parseString !==
'') {
1423 if ($stopRegex && ($this->lastStopKeyWord = $this->
nextPart($parseString, $stopRegex))) {
1427 return $this->
parseError(
'No operator, but parsing not finished in parseWhereClause().', $parseString);
1433 if ($loopExit > 500) {
1434 return $this->
parseError(
'More than 500 loops, exiting prematurely in parseWhereClause()...', $parseString);
1452 $parseString = $this->
trimSQL($parseString);
1453 $this->lastStopKeyWord =
'';
1454 $this->parse_error =
'';
1457 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|date|datetime|time|year|timestamp)([[:space:],]+|\\()')) {
1459 if ($parseString[0] ===
'(') {
1460 $parseString = substr($parseString, 1);
1461 if ($result[
'value'] = $this->
nextPart($parseString,
'^([^)]*)')) {
1462 $parseString = ltrim(substr($parseString, 1));
1464 return $this->
parseError(
'No end-parenthesis for value found in parseFieldDef()!', $parseString);
1468 while ($keyword = $this->
nextPart($parseString,
'^(DEFAULT|NOT[[:space:]]+NULL|AUTO_INCREMENT|UNSIGNED)([[:space:]]+|,|\\))')) {
1470 $result[
'featureIndex'][$keywordCmp][
'keyword'] = $keyword;
1471 switch ($keywordCmp) {
1473 $result[
'featureIndex'][$keywordCmp][
'value'] = $this->
getValue($parseString);
1478 return $this->
parseError(
'Field type unknown in parseFieldDef()!', $parseString);
1492 if (!is_array($featureIndex[
'DEFAULT'][
'value'])) {
1495 return !is_numeric($featureIndex[
'DEFAULT'][
'value'][0]) && empty($featureIndex[
'DEFAULT'][
'value'][0]);
1512 protected function nextPart(&$parseString, $regex, $trimAll =
false)
1516 if (preg_match(
'/' . $regex .
'/i', $parseString .
' ', $reg)) {
1517 $parseString = ltrim(substr($parseString, strlen($reg[$trimAll ? 0 : 1])));
1532 return strtoupper(str_replace(self::$interQueryWhitespaces,
'', $keyword));
1546 protected function &
getValueOrParameter(&$parseString, $comparator =
'', $mode =
'', array &$parameterReferences = array())
1548 $parameter = $this->
nextPart($parseString,
'^(\\:[[:alnum:]_]+|\\?)');
1549 if ($parameter ===
'?') {
1550 if (!isset($parameterReferences[
'?'])) {
1551 $parameterReferences[
'?'] = array();
1553 $value = array(
'?');
1554 $parameterReferences[
'?'][] = &$value;
1555 }
elseif ($parameter !==
'') {
1557 if (isset($parameterReferences[$parameter])) {
1559 $value = &$parameterReferences[$parameter];
1561 $value = array($parameter);
1562 $parameterReferences[$parameter] = &$value;
1565 $value = $this->
getValue($parseString, $comparator, $mode);
1578 protected function getValue(&$parseString, $comparator =
'', $mode =
'')
1581 if (
GeneralUtility::inList(
'NOTIN,IN,_LIST', strtoupper(str_replace(array(
' ', LF, CR, TAB),
'', $comparator)))) {
1583 if ($this->
nextPart($parseString,
'^([(])')) {
1584 $listValues = array();
1586 while ($comma ===
',') {
1587 $listValues[] = $this->
getValue($parseString);
1588 if ($mode ===
'INDEX') {
1590 $this->
nextPart($parseString,
'^([(]\\d+[)])');
1592 $comma = $this->
nextPart($parseString,
'^([,])');
1594 $out = $this->
nextPart($parseString,
'^([)])');
1596 if ($comparator ===
'_LIST') {
1598 foreach ($listValues as $vArr) {
1599 $kVals[] = $vArr[0];
1606 return array($this->
parseError(
'No ) parenthesis in list', $parseString));
1609 return array($this->
parseError(
'No ( parenthesis starting the list', $parseString));
1614 $firstChar = $parseString[0];
1615 switch ($firstChar) {
1624 if (preg_match(
'/^([[:alnum:]._-]+(?:\\([0-9]+\\))?)/i', $parseString, $reg)) {
1625 $parseString = ltrim(substr($parseString, strlen($reg[0])));
1626 $value = array($reg[1]);
1642 $search = array(
'\\\\',
'\\\'',
'\\"',
'\0',
'\n',
'\r',
'\Z');
1643 $replace = array(
'\\',
'\'',
'"',
"\x00",
"\x0a",
"\x0d",
"\x1a");
1645 return str_replace($search, $replace, $str);
1657 $this->parse_error =
'SQL engine parse ERROR: ' . $msg .
': near "' . substr($restQuery, 0, 50) .
'"';
1672 return rtrim(rtrim(trim($str),
';')) .
' ';
1704 return $this->
getSqlCompiler()->compileFieldList($selectFields, $compileComments);
1748 return $this->
getSqlCompiler()->compileWhereClause($clauseArray, $functionMapping);
1756 if ((
string)$this->databaseConnection->handlerCfg[$this->databaseConnection->lastHandlerKey][
'type'] ===
'native') {
1777 $parseResult = $this->
parseSQL($SQLquery);
1779 if (is_array($parseResult)) {
1785 if (!is_array($testResult)) {
1788 debug(array(
'ERROR MESSAGE' =>
'Input query did not match the parsed and recompiled query exactly (not observing whitespace)',
'TEST result' => $testResult),
'SQL parsing failed:');
1792 debug(array(
'query' => $SQLquery,
'ERROR MESSAGE' => $parseResult),
'SQL parsing failed:');
1831 if ($caseInsensitive) {
1832 $str1 = strtoupper($str);
1833 $str2 = strtoupper($newStr);
1840 $search = array(NUL, LF, CR, SUB);
1841 $replace = array(
"\x00",
"\x0a",
"\x0d",
"\x1a");
1842 $str1 = str_replace($search, $replace, $str1);
1843 $str2 = str_replace($search, $replace, $str2);
1845 $search = self::$interQueryWhitespaces;
1846 if (str_replace($search,
'', $this->
trimSQL($str1)) !== str_replace($search,
'', $this->
trimSQL($str2))) {
1848 str_replace($search,
' ', $str),
1849 str_replace($search,
' ', $newStr),