protected function processExpressionList($unparsed)
 {
     $processor = new ExpressionListProcessor();
     $expr = $this->removeParenthesisFromStart($unparsed);
     $expr = $this->splitSQLIntoTokens($expr);
     return $processor->process($expr);
 }
 protected function processFromExpression(&$parseInfo)
 {
     $res = array();
     // exchange the join types (join_type is save now, saved_join_type holds the next one)
     $parseInfo['join_type'] = $parseInfo['saved_join_type'];
     // initialized with JOIN
     $parseInfo['saved_join_type'] = $parseInfo['next_join_type'] ? $parseInfo['next_join_type'] : 'JOIN';
     // we have a reg_expr, so we have to parse it
     if ($parseInfo['ref_expr'] !== false) {
         $unparsed = $this->splitSQLIntoTokens($this->removeParenthesisFromStart($parseInfo['ref_expr']));
         // here we can get a comma separated list
         foreach ($unparsed as $k => $v) {
             if ($this->isCommaToken($v)) {
                 $unparsed[$k] = "";
             }
         }
         $processor = new ExpressionListProcessor();
         $parseInfo['ref_expr'] = $processor->process($unparsed);
     }
     // there is an expression, we have to parse it
     if (substr(trim($parseInfo['table']), 0, 1) == '(') {
         $parseInfo['expression'] = $this->removeParenthesisFromStart($parseInfo['table']);
         if (preg_match("/^\\s*select/i", $parseInfo['expression'])) {
             $processor = new DefaultProcessor();
             $parseInfo['sub_tree'] = $processor->process($parseInfo['expression']);
             $res['expr_type'] = ExpressionType::SUBQUERY;
         } else {
             $tmp = $this->splitSQLIntoTokens($parseInfo['expression']);
             $parseInfo['sub_tree'] = $this->process($tmp);
             $res['expr_type'] = ExpressionType::TABLE_EXPRESSION;
         }
     } else {
         $res['expr_type'] = ExpressionType::TABLE;
         $res['table'] = $parseInfo['table'];
         $res['no_quotes'] = $this->revokeQuotation($parseInfo['table']);
     }
     $res['alias'] = $parseInfo['alias'];
     $res['join_type'] = $parseInfo['join_type'];
     $res['ref_type'] = $parseInfo['ref_type'];
     $res['ref_clause'] = $parseInfo['ref_expr'];
     $res['base_expr'] = trim($parseInfo['expression']);
     $res['sub_tree'] = $parseInfo['sub_tree'];
     return $res;
 }
 public function process($tokens, $select = array())
 {
     $parsed = parent::process($tokens);
     foreach ($parsed as $k => $v) {
         if ($v['expr_type'] === ExpressionType::COLREF) {
             foreach ($select as $clause) {
                 if (!$clause['alias']) {
                     continue;
                 }
                 if ($clause['alias']['no_quotes'] === $v['no_quotes']) {
                     $parsed[$k]['expr_type'] = ExpressionType::ALIAS;
                     break;
                 }
             }
         }
     }
     return $parsed;
 }
 protected function processExpressionList($parsed)
 {
     $processor = new ExpressionListProcessor();
     return $processor->process($parsed);
 }
 public function process($tokens)
 {
     $base_expr = "";
     $prevCategory = "";
     $currCategory = "";
     $expr = array();
     $result = array();
     $skip = 0;
     foreach ($tokens as $k => $token) {
         $trim = trim($token);
         $base_expr .= $token;
         if ($skip !== 0) {
             $skip--;
             continue;
         }
         if ($trim === "") {
             continue;
         }
         $upper = strtoupper($trim);
         switch ($upper) {
             case 'CONSTRAINT':
                 $expr[] = array('expr_type' => ExpressionType::CONSTRAINT, 'base_expr' => $trim, 'sub_tree' => false);
                 $currCategory = $prevCategory = $upper;
                 continue 2;
             case 'LIKE':
                 $expr[] = array('expr_type' => ExpressionType::LIKE, 'base_expr' => $trim);
                 $currCategory = $prevCategory = $upper;
                 continue 2;
             case 'FOREIGN':
                 if ($prevCategory === "" || $prevCategory === "CONSTRAINT") {
                     $expr[] = array('expr_type' => ExpressionType::FOREIGN_KEY, 'base_expr' => $trim);
                     $currCategory = $upper;
                     continue 2;
                 }
                 # else ?
                 break;
             case 'PRIMARY':
                 if ($prevCategory === "" || $prevCategory === "CONSTRAINT") {
                     # next one is KEY
                     $expr[] = array('expr_type' => ExpressionType::PRIMARY_KEY, 'base_expr' => $trim);
                     $currCategory = $upper;
                     continue 2;
                 }
                 # else ?
                 break;
             case 'UNIQUE':
                 if ($prevCategory === "" || $prevCategory === "CONSTRAINT") {
                     # next one is KEY
                     $expr[] = array('expr_type' => ExpressionType::UNIQUE_IDX, 'base_expr' => $trim);
                     $currCategory = $upper;
                     continue 2;
                 }
                 # else ?
                 break;
             case 'KEY':
                 # the next one is an index name
                 if ($currCategory === 'PRIMARY' || $currCategory === 'FOREIGN' || $currCategory === 'UNIQUE') {
                     $expr[] = array('expr_type' => ExpressionType::RESERVED, 'base_expr' => $trim);
                     continue 2;
                 }
                 $expr[] = array('expr_type' => ExpressionType::INDEX, 'base_expr' => $trim);
                 $currCategory = $upper;
                 continue 2;
             case 'CHECK':
                 $expr[] = array('expr_type' => ExpressionType::CHECK, 'base_expr' => $trim);
                 $currCategory = $upper;
                 continue 2;
             case 'INDEX':
                 if ($currCategory === 'UNIQUE' || $currCategory === 'FULLTEXT' || $currCategory === 'SPATIAL') {
                     $expr[] = array('expr_type' => ExpressionType::RESERVED, 'base_expr' => $trim);
                     continue 2;
                 }
                 $expr[] = array('expr_type' => ExpressionType::INDEX, 'base_expr' => $trim);
                 $currCategory = $upper;
                 continue 2;
             case 'FULLTEXT':
                 $expr[] = array('expr_type' => ExpressionType::FULLTEXT_IDX, 'base_expr' => $trim);
                 $currCategory = $prevCategory = $upper;
                 continue 2;
             case 'SPATIAL':
                 $expr[] = array('expr_type' => ExpressionType::SPATIAL_IDX, 'base_expr' => $trim);
                 $currCategory = $prevCategory = $upper;
                 continue 2;
             case 'WITH':
                 # starts an index option
                 if ($currCategory === 'INDEX_COL_LIST') {
                     $option = array('expr_type' => ExpressionType::RESERVED, 'base_expr' => $trim);
                     $expr[] = array('expr_type' => ExpressionType::INDEX_PARSER, 'base_expr' => substr($base_expr, 0, -strlen($token)), 'sub_tree' => array($option));
                     $base_expr = $token;
                     $currCategory = 'INDEX_PARSER';
                     continue 2;
                 }
                 break;
             case 'KEY_BLOCK_SIZE':
                 # starts an index option
                 if ($currCategory === 'INDEX_COL_LIST') {
                     $option = array('expr_type' => ExpressionType::RESERVED, 'base_expr' => $trim);
                     $expr[] = array('expr_type' => ExpressionType::INDEX_SIZE, 'base_expr' => substr($base_expr, 0, -strlen($token)), 'sub_tree' => array($option));
                     $base_expr = $token;
                     $currCategory = 'INDEX_SIZE';
                     continue 2;
                 }
                 break;
             case 'USING':
                 # starts an index option
                 if ($currCategory === 'INDEX_COL_LIST' || $currCategory === 'PRIMARY') {
                     $option = array('expr_type' => ExpressionType::RESERVED, 'base_expr' => $trim);
                     $expr[] = array('base_expr' => substr($base_expr, 0, -strlen($token)), 'trim' => $trim, 'category' => $currCategory, 'sub_tree' => array($option));
                     $base_expr = $token;
                     $currCategory = 'INDEX_TYPE';
                     continue 2;
                 }
                 # else ?
                 break;
             case 'REFERENCES':
                 if ($currCategory === 'INDEX_COL_LIST' && $prevCategory === 'FOREIGN') {
                     $processor = new ReferenceDefinitionProcessor();
                     $refs = $processor->process(array_slice($tokens, $k - 1, null, true));
                     $skip = $refs['till'] - $k;
                     unset($refs['till']);
                     $expr[] = $refs;
                     $currCategory = $upper;
                 }
                 break;
             case 'BTREE':
             case 'HASH':
                 if ($currCategory === 'INDEX_TYPE') {
                     $last = array_pop($expr);
                     $last['sub_tree'][] = array('expr_type' => ExpressionType::RESERVED, 'base_expr' => $trim);
                     $expr[] = array('expr_type' => ExpressionType::INDEX_TYPE, 'base_expr' => $base_expr, 'sub_tree' => $last['sub_tree']);
                     $base_expr = $last['base_expr'] . $base_expr;
                     # FIXME: it could be wrong for index_type within index_option
                     $currCategory = $last['category'];
                     continue 2;
                 }
                 #else
                 break;
             case '=':
                 if ($currCategory === 'INDEX_SIZE') {
                     # the optional character between KEY_BLOCK_SIZE and the numeric constant
                     $last = array_pop($expr);
                     $last['sub_tree'][] = array('expr_type' => ExpressionType::RESERVED, 'base_expr' => $trim);
                     $expr[] = $last;
                     continue 2;
                 }
                 break;
             case 'PARSER':
                 if ($currCategory === 'INDEX_PARSER') {
                     $last = array_pop($expr);
                     $last['sub_tree'][] = array('expr_type' => ExpressionType::RESERVED, 'base_expr' => $trim);
                     $expr[] = $last;
                     continue 2;
                 }
                 # else?
                 break;
             case ',':
                 # this starts the next definition
                 $type = $this->correctExpressionType($expr);
                 $result['create-def'][] = array('expr_type' => $type, 'base_expr' => trim(substr($base_expr, 0, -strlen($token))), 'sub_tree' => $expr);
                 $base_expr = "";
                 $expr = array();
                 break;
             default:
                 switch ($currCategory) {
                     case 'LIKE':
                         # this is the tablename after LIKE
                         $expr[] = array('expr_type' => ExpressionType::TABLE, 'table' => $trim, 'base_expr' => $trim, 'no_quotes' => $this->revokeQuotation($trim));
                         break;
                     case 'PRIMARY':
                         if ($upper[0] === '(' && substr($upper, -1) === ')') {
                             # the column list
                             $processor = new IndexColumnListProcessor();
                             $cols = $processor->process($this->removeParenthesisFromStart($trim));
                             $expr[] = array('expr_type' => ExpressionType::COLUMN_LIST, 'base_expr' => $trim, 'sub_tree' => $cols);
                             $prevCategory = $currCategory;
                             $currCategory = "INDEX_COL_LIST";
                             continue 3;
                         }
                         # else?
                         break;
                     case 'FOREIGN':
                         if ($upper[0] === '(' && substr($upper, -1) === ')') {
                             $processor = new IndexColumnListProcessor();
                             $cols = $processor->process($this->removeParenthesisFromStart($trim));
                             $expr[] = array('expr_type' => ExpressionType::COLUMN_LIST, 'base_expr' => $trim, 'sub_tree' => $cols);
                             $prevCategory = $currCategory;
                             $currCategory = "INDEX_COL_LIST";
                             continue 3;
                         }
                         # index name
                         $expr[] = array('expr_type' => ExpressionType::CONSTANT, 'base_expr' => $trim);
                         continue 3;
                     case 'KEY':
                     case 'UNIQUE':
                     case 'INDEX':
                         if ($upper[0] === '(' && substr($upper, -1) === ')') {
                             $processor = new IndexColumnListProcessor();
                             $cols = $processor->process($this->removeParenthesisFromStart($trim));
                             $expr[] = array('expr_type' => ExpressionType::COLUMN_LIST, 'base_expr' => $trim, 'sub_tree' => $cols);
                             $prevCategory = $currCategory;
                             $currCategory = "INDEX_COL_LIST";
                             continue 3;
                         }
                         # index name
                         $expr[] = array('expr_type' => ExpressionType::CONSTANT, 'base_expr' => $trim);
                         continue 3;
                     case 'CONSTRAINT':
                         # constraint name
                         $last = array_pop($expr);
                         $last['base_expr'] = $base_expr;
                         $last['sub_tree'] = array('expr_type' => ExpressionType::CONSTANT, 'base_expr' => $trim);
                         $expr[] = $last;
                         continue 3;
                     case 'INDEX_PARSER':
                         # index parser name
                         $last = array_pop($expr);
                         $last['sub_tree'][] = array('expr_type' => ExpressionType::CONSTANT, 'base_expr' => $trim);
                         $expr[] = array('expr_type' => ExpressionType::INDEX_PARSER, 'base_expr' => $base_expr, 'sub_tree' => $last['sub_tree']);
                         $base_expr = $last['base_expr'] . $base_expr;
                         $currCategory = 'INDEX_COL_LIST';
                         continue 3;
                     case 'INDEX_SIZE':
                         # index key block size numeric constant
                         $last = array_pop($expr);
                         $last['sub_tree'][] = array('expr_type' => ExpressionType::CONSTANT, 'base_expr' => $trim);
                         $expr[] = array('expr_type' => ExpressionType::INDEX_SIZE, 'base_expr' => $base_expr, 'sub_tree' => $last['sub_tree']);
                         $base_expr = $last['base_expr'] . $base_expr;
                         $currCategory = 'INDEX_COL_LIST';
                         continue 3;
                     case 'CHECK':
                         if ($upper[0] === '(' && substr($upper, -1) === ')') {
                             $processor = new ExpressionListProcessor();
                             $unparsed = $this->splitSQLIntoTokens($this->removeParenthesisFromStart($trim));
                             $parsed = $processor->process($unparsed);
                             $expr[] = array('expr_type' => ExpressionType::BRACKET_EXPRESSION, 'base_expr' => $trim, 'sub_tree' => $parsed);
                         }
                         # else?
                         break;
                     case '':
                         # if the currCategory is empty, we have an unknown token,
                         # which is a column reference
                         $expr[] = array('expr_type' => ExpressionType::COLREF, 'base_expr' => $trim, 'no_quotes' => $this->revokeQuotation($trim));
                         $currCategory = 'COLUMN_NAME';
                         continue 3;
                     case 'COLUMN_NAME':
                         # the column-definition
                         # it stops on a comma or on a parenthesis
                         $processor = new ColumnDefinitionProcessor();
                         $parsed = $processor->process(array_slice($tokens, $k, null, true), $expr);
                         $skip = $parsed['till'] - $k;
                         unset($parsed['till']);
                         $expr[] = $parsed;
                         $currCategory = '';
                         break;
                     default:
                         # ?
                         break;
                 }
                 break;
         }
         $prevCategory = $currCategory;
         $currCategory = '';
     }
     $type = $this->correctExpressionType($expr);
     $result['create-def'][] = array('expr_type' => $type, 'base_expr' => trim($base_expr), 'sub_tree' => $expr);
     return $result;
 }
 protected function processExpressionList($tokens)
 {
     $processor = new ExpressionListProcessor();
     return $processor->process($tokens);
 }
 protected function processExpressionList($unparsed)
 {
     $processor = new ExpressionListProcessor($this->options);
     return $processor->process($unparsed);
 }