Viewing file: Parser.php (42.02 KB) -rw-rw-rw- Select action/file-type: (+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
<?php /* vim: set expandtab tabstop=4 shiftwidth=4: */ // +----------------------------------------------------------------------+ // | Copyright (c) 2002-2004 Brent Cook | // +----------------------------------------------------------------------+ // | This library is free software; you can redistribute it and/or | // | modify it under the terms of the GNU Lesser General Public | // | License as published by the Free Software Foundation; either | // | version 2.1 of the License, or (at your option) any later version. | // | | // | This library 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 | // | Lesser General Public License for more details. | // | | // | You should have received a copy of the GNU Lesser General Public | // | License along with this library; if not, write to the Free Software | // | Foundation, Inc., 59 Temple Place, Suite 330,Boston,MA 02111-1307 USA| // +----------------------------------------------------------------------+ // | Authors: Brent Cook <busterbcook@yahoo.com> | // | Jason Pell <jasonpell@hotmail.com> | // | Lauren Matheson <inan@canada.com> | // | John Griffin <jgriffin316@netscape.net> | // +----------------------------------------------------------------------+ // // $Id: Parser.php,v 1.23 2004/05/11 05:09:02 busterb Exp $ //
require_once 'PEAR.php'; require_once 'SQL/Lexer.php';
/** * A sql parser * * @author Brent Cook <busterbcook@yahoo.com> * @version 0.5 * @access public * @package SQL_Parser */ class SQL_Parser { var $lexer; var $token;
// symbol definitions var $functions = array(); var $types = array(); var $symbols = array(); var $operators = array(); var $synonyms = array();
var $dialects = array("ANSI", "MySQL");
// {{{ function SQL_Parser($string = null) function SQL_Parser($string = null, $dialect = "ANSI") { $this->setDialect($dialect);
if (is_string($string)) { $this->lexer = new Lexer($string, 1); $this->lexer->symbols =& $this->symbols; } } // }}}
// {{{ function setDialect($dialect) function setDialect($dialect) { if (in_array($dialect, $this->dialects)) { include 'SQL/Dialect_'.$dialect.'.php'; $this->types = array_flip($dialect['types']); $this->functions = array_flip($dialect['functions']); $this->operators = array_flip($dialect['operators']); $this->commands = array_flip($dialect['commands']); $this->synonyms = $dialect['synonyms']; $this->symbols = array_merge( $this->types, $this->functions, $this->operators, $this->commands, array_flip($dialect['reserved']), array_flip($dialect['conjunctions'])); } else { return $this->raiseError('Unknown SQL dialect:'.$dialect); } } // }}} // {{{ getParams(&$values, &$types) function getParams(&$values, &$types) { $values = array(); $types = array(); while ($this->token != ')') { $this->getTok(); if ($this->isVal() || ($this->token == 'ident')) { $values[] = $this->lexer->tokText; $types[] = $this->token; } elseif ($this->token == ')') { return false; } else { return $this->raiseError('Expected a value'); } $this->getTok(); if (($this->token != ',') && ($this->token != ')')) { return $this->raiseError('Expected , or )'); } } } // }}}
// {{{ raiseError($message) function raiseError($message) { $end = 0; if ($this->lexer->string != '') { while (($this->lexer->lineBegin+$end < $this->lexer->stringLen) && ($this->lexer->string{$this->lexer->lineBegin+$end} != "\n")){ ++$end; } } $message = 'Parse error: '.$message.' on line '. ($this->lexer->lineNo+1)."\n"; $message .= substr($this->lexer->string, $this->lexer->lineBegin, $end)."\n"; $length = is_null($this->token) ? 0 : strlen($this->lexer->tokText); $message .= str_repeat(' ', abs($this->lexer->tokPtr - $this->lexer->lineBegin - $length))."^"; $message .= ' found: "'.$this->lexer->tokText.'"';
return PEAR::raiseError($message); } // }}}
// {{{ isType() function isType() { return isset($this->types[$this->token]); } // }}}
// {{{ isVal() function isVal() { return (($this->token == 'real_val') || ($this->token == 'int_val') || ($this->token == 'text_val') || ($this->token == 'null')); } // }}}
// {{{ isFunc() function isFunc() { return isset($this->functions[$this->token]); } // }}}
// {{{ isCommand() function isCommand() { return isset($this->commands[$this->token]); } // }}}
// {{{ isReserved() function isReserved() { return isset($this->symbols[$this->token]); } // }}}
// {{{ isOperator() function isOperator() { return isset($this->operators[$this->token]); } // }}}
// {{{ getTok() function getTok() { $this->token = $this->lexer->lex(); //echo $this->token."\t".$this->lexer->tokText."\n"; } // }}}
// {{{ &parseFieldOptions() function parseFieldOptions() { // parse field options $namedConstraint = false; $options = array(); while (($this->token != ',') && ($this->token != ')') && ($this->token != null)) { $option = $this->token; $haveValue = true; switch ($option) { case 'constraint': $this->getTok(); if ($this->token = 'ident') { $constraintName = $this->lexer->tokText; $namedConstraint = true; $haveValue = false; } else { return $this->raiseError('Expected a constraint name'); } break; case 'default': $this->getTok(); if ($this->isVal()) { $constraintOpts = array('type'=>'default_value', 'value'=>$this->lexer->tokText); } elseif ($this->isFunc()) { $results = $this->parseFunctionOpts(); if (PEAR::isError($results)) { return $results; } $results['type'] = 'default_function'; $constraintOpts = $results; } else { return $this->raiseError('Expected default value'); } break; case 'primary': $this->getTok(); if ($this->token == 'key') { $constraintOpts = array('type'=>'primary_key', 'value'=>true); } else { return $this->raiseError('Expected "key"'); } break; case 'not': $this->getTok(); if ($this->token == 'null') { $constraintOpts = array('type'=>'not_null', 'value' => true); } else { return $this->raiseError('Expected "null"'); } break; case 'check': $this->getTok(); if ($this->token != '(') { return $this->raiseError('Expected ('); } $results = $this->parseSearchClause(); if (PEAR::isError($results)) { return $results; } $results['type'] = 'check'; $constraintOpts = $results; if ($this->token != ')') { return $this->raiseError('Expected )'); } break; case 'unique': $this->getTok(); if ($this->token != '(') { return $this->raiseError('Expected ('); } $constraintOpts = array('type'=>'unique'); $this->getTok(); while ($this->token != ')') { if ($this->token != 'ident') { return $this->raiseError('Expected an identifier'); } $constraintOpts['column_names'][] = $this->lexer->tokText; $this->getTok(); if (($this->token != ')') && ($this->token != ',')) { return $this->raiseError('Expected ) or ,'); } } if ($this->token != ')') { return $this->raiseError('Expected )'); } break; case 'month': case 'year': case 'day': case 'hour': case 'minute': case 'second': $intervals = array( array('month'=>0, 'year'=>1), array('second'=>0, 'minute'=>1, 'hour'=>2, 'day'=>3)); foreach ($intervals as $class) { if (isset($class[$option])) { $constraintOpts = array('quantum_1'=>$this->token); $this->getTok(); if ($this->token == 'to') { $this->getTok(); if (!isset($class[$this->token])) { return $this->raiseError( 'Expected interval quanta'); } if ($class[$this->token] >= $class[$constraintOpts['quantum_1']]) { return $this->raiseError($this->token. ' is not smaller than '. $constraintOpts['quantum_1']); } $constraintOpts['quantum_2'] = $this->token; } else { $this->lexer->unget(); } break; } } if (!isset($constraintOpts['quantum_1'])) { return $this->raiseError('Expected interval quanta'); } $constraintOpts['type'] = 'values'; break; case 'null': $haveValue = false; break; default: return $this->raiseError('Unexpected token ' .$this->lexer->tokText); } if ($haveValue) { if ($namedConstraint) { $options['constraints'][$constraintName] = $constraintOpts; $namedConstraint = false; } else { $options['constraints'][] = $constraintOpts; } } $this->getTok(); } return $options; } // }}}
// {{{ parseSearchClause() function parseSearchClause($subSearch = false) { $clause = array(); // parse the first argument $this->getTok(); if ($this->token == 'not') { $clause['neg'] = true; $this->getTok(); }
$foundSubclause = false; if ($this->token == '(') { $clause['arg_1']['value'] = $this->parseSearchClause(true); $clause['arg_1']['type'] = 'subclause'; if ($this->token != ')') { return $this->raiseError('Expected ")"'); } $foundSubclause = true; } else if ($this->isReserved()) { return $this->raiseError('Expected a column name or value'); } else { $clause['arg_1']['value'] = $this->lexer->tokText; $clause['arg_1']['type'] = $this->token; }
// parse the operator if (!$foundSubclause) { $this->getTok(); if (!$this->isOperator()) { return $this->raiseError('Expected an operator'); } $clause['op'] = $this->token;
$this->getTok(); switch ($clause['op']) { case 'is': // parse for 'is' operator if ($this->token == 'not') { $clause['neg'] = true; $this->getTok(); } if ($this->token != 'null') { return $this->raiseError('Expected "null"'); } $clause['arg_2']['value'] = ''; $clause['arg_2']['type'] = $this->token; break; case 'not': // parse for 'not in' operator if ($this->token != 'in') { return $this->raiseError('Expected "in"'); } $clause['op'] = $this->token; $clause['neg'] = true; $this->getTok(); case 'in': // parse for 'in' operator if ($this->token != '(') { return $this->raiseError('Expected "("'); }
// read the subset $this->getTok(); // is this a subselect? if ($this->token == 'select') { $clause['arg_2']['value'] = $this->parseSelect(true); $clause['arg_2']['type'] = 'command'; } else { $this->lexer->pushBack(); // parse the set $result = $this->getParams($clause['arg_2']['value'], $clause['arg_2']['type']); if (PEAR::isError($result)) { return $result; } } if ($this->token != ')') { return $this->raiseError('Expected ")"'); } break; case 'and': case 'or': $this->lexer->unget(); break; default: // parse for in-fix binary operators if ($this->isReserved()) { return $this->raiseError('Expected a column name or value'); } if ($this->token == '(') { $clause['arg_2']['value'] = $this->parseSearchClause(true); $clause['arg_2']['type'] = 'subclause'; $this->getTok(); if ($this->token != ')') { return $this->raiseError('Expected ")"'); } } else { $clause['arg_2']['value'] = $this->lexer->tokText; $clause['arg_2']['type'] = $this->token; } } }
$this->getTok(); if (($this->token == 'and') || ($this->token == 'or')) { $op = $this->token; $subClause = $this->parseSearchClause($subSearch); if (PEAR::isError($subClause)) { return $subClause; } else { $clause = array('arg_1' => $clause, 'op' => $op, 'arg_2' => $subClause); } } else { $this->lexer->unget(); } return $clause; } // }}}
// {{{ parseFieldList() function parseFieldList() { $this->getTok(); if ($this->token != '(') { return $this->raiseError('Expected ('); }
$fields = array(); while (1) { // parse field identifier $this->getTok(); if ($this->token == 'ident') { $name = $this->lexer->tokText; } elseif ($this->token == ')') { return $fields; } else { return $this->raiseError('Expected identifier'); }
// parse field type $this->getTok(); if ($this->isType($this->token)) { $type = $this->token; } else { return $this->raiseError('Expected a valid type'); }
$this->getTok(); // handle special case two-word types if ($this->token == 'precision') { // double precision == double if ($type == 'double') { return $this->raiseError('Unexpected token'); } $this->getTok(); } elseif ($this->token == 'varying') { // character varying() == varchar() if ($type == 'character') { $type == 'varchar'; $this->getTok(); } else { return $this->raiseError('Unexpected token'); } } $fields[$name]['type'] = $this->synonyms[$type]; // parse type parameters if ($this->token == '(') { $results = $this->getParams($values, $types); if (PEAR::isError($results)) { return $results; } switch ($fields[$name]['type']) { case 'numeric': if (isset($values[1])) { if ($types[1] != 'int_val') { return $this->raiseError('Expected an integer'); } $fields[$name]['decimals'] = $values[1]; } case 'float': if ($types[0] != 'int_val') { return $this->raiseError('Expected an integer'); } $fields[$name]['length'] = $values[0]; break; case 'char': case 'varchar': case 'integer': case 'int': if (sizeof($values) != 1) { return $this->raiseError('Expected 1 parameter'); } if ($types[0] != 'int_val') { return $this->raiseError('Expected an integer'); } $fields[$name]['length'] = $values[0]; break; case 'set': case 'enum': if (!sizeof($values)) { return $this->raiseError('Expected a domain'); } $fields[$name]['domain'] = $values; break; default: if (sizeof($values)) { return $this->raiseError('Unexpected )'); } } $this->getTok(); }
$options = $this->parseFieldOptions(); if (PEAR::isError($options)) { return $options; }
$fields[$name] += $options;
if ($this->token == ')') { return $fields; } elseif (is_null($this->token)) { return $this->raiseError('Expected )'); } } } // }}}
// {{{ parseFunctionOpts() function parseFunctionOpts() { $function = $this->token; $opts['name'] = $function; $this->getTok(); if ($this->token != '(') { return $this->raiseError('Expected "("'); } switch ($function) { case 'count': $this->getTok(); switch ($this->token) { case 'distinct': $opts['distinct'] = true; $this->getTok(); if ($this->token != 'ident') { return $this->raiseError('Expected a column name'); } case 'ident': case '*': $opts['arg'][] = $this->lexer->tokText; break; default: return $this->raiseError('Invalid argument'); } break; case 'concat': $this->getTok(); while ($this->token != ')') { switch ($this->token) { case 'ident': case 'text_val': $opts['arg'][] = $this->lexer->tokText; break; case ',': // do nothing break; default: return $this->raiseError('Expected a string or a column name'); } $this->getTok(); } $this->lexer->pushBack(); break; case 'avg': case 'min': case 'max': case 'sum': default: $this->getTok(); $opts['arg'] = $this->lexer->tokText; break; } $this->getTok(); if ($this->token != ')') { return $this->raiseError('Expected ")"'); } // check for an alias $this->getTok(); if ($this->token == ',' || $this->token == 'from') { $this->lexer->pushBack(); } elseif ($this->token == 'as') { $this->getTok(); if ($this->token == 'ident' ) { $opts['alias'] = $this->lexer->tokText; } else { return $this->raiseError('Expected column alias'); } } else { if ($this->token == 'ident' ) { $opts['alias'] = $this->lexer->tokText; } else { return $this->raiseError('Expected column alias, from or comma'); } } return $opts; } // }}}
// {{{ parseCreate() function parseCreate() { $this->getTok(); switch ($this->token) { case 'table': $tree = array('command' => 'create_table'); $this->getTok(); if ($this->token == 'ident') { $tree['table_names'][] = $this->lexer->tokText; $fields = $this->parseFieldList(); if (PEAR::isError($fields)) { return $fields; } $tree['column_defs'] = $fields; // $tree['column_names'] = array_keys($fields); } else { return $this->raiseError('Expected table name'); } break; case 'index': $tree = array('command' => 'create_index'); break; case 'constraint': $tree = array('command' => 'create_constraint'); break; case 'sequence': $tree = array('command' => 'create_sequence'); break; default: return $this->raiseError('Unknown object to create'); } return $tree; } // }}}
// {{{ parseInsert() function parseInsert() { $this->getTok(); if ($this->token == 'into') { $tree = array('command' => 'insert'); $this->getTok(); if ($this->token == 'ident') { $tree['table_names'][] = $this->lexer->tokText; $this->getTok(); } else { return $this->raiseError('Expected table name'); } if ($this->token == '(') { $results = $this->getParams($values, $types); if (PEAR::isError($results)) { return $results; } else { if (sizeof($values)) { $tree['column_names'] = $values; } } $this->getTok(); } if ($this->token == 'values') { $this->getTok(); $results = $this->getParams($values, $types); if (PEAR::isError($results)) { return $results; } else { if (isset($tree['column_defs']) && (sizeof($tree['column_defs']) != sizeof($values))) { return $this->raiseError('field/value mismatch'); } if (sizeof($values)) { foreach ($values as $key=>$value) { $values[$key] = array('value'=>$value, 'type'=>$types[$key]); } $tree['values'] = $values; } else { return $this->raiseError('No fields to insert'); } } } else { return $this->raiseError('Expected "values"'); } } else { return $this->raiseError('Expected "into"'); } return $tree; } // }}}
// {{{ parseUpdate() function parseUpdate() { $this->getTok(); if ($this->token == 'ident') { $tree = array('command' => 'update'); $tree['table_names'][] = $this->lexer->tokText; } else { return $this->raiseError('Expected table name'); } $this->getTok(); if ($this->token != 'set') { return $this->raiseError('Expected "set"'); } while (true) { $this->getTok(); if ($this->token != 'ident') { return $this->raiseError('Expected a column name'); } $tree['column_names'][] = $this->lexer->tokText; $this->getTok(); if ($this->token != '=') { return $this->raiseError('Expected ='); } $this->getTok(); if (!$this->isVal($this->token)) { return $this->raiseError('Expected a value'); } $tree['values'][] = array('value'=>$this->lexer->tokText, 'type'=>$this->token); $this->getTok(); if ($this->token == 'where') { $clause = $this->parseSearchClause(); if (PEAR::isError($clause)) { return $clause; } $tree['where_clause'] = $clause; break; } elseif ($this->token != ',') { return $this->raiseError('Expected "where" or ","'); } } return $tree; } // }}}
// {{{ parseDelete() function parseDelete() { $this->getTok(); if ($this->token != 'from') { return $this->raiseError('Expected "from"'); } $tree = array('command' => 'delete'); $this->getTok(); if ($this->token != 'ident') { return $this->raiseError('Expected a table name'); } $tree['table_names'][] = $this->lexer->tokText; $this->getTok(); if ($this->token != 'where') { return $this->raiseError('Expected "where"'); } $clause = $this->parseSearchClause(); if (PEAR::isError($clause)) { return $clause; } $tree['where_clause'] = $clause; return $tree; } // }}}
// {{{ parseDrop() function parseDrop() { $this->getTok(); switch ($this->token) { case 'table': $tree = array('command' => 'drop_table'); $this->getTok(); if ($this->token != 'ident') { return $this->raiseError('Expected a table name'); } $tree['table_names'][] = $this->lexer->tokText; $this->getTok(); if (($this->token == 'restrict') || ($this->token == 'cascade')) { $tree['drop_behavior'] = $this->token; } $this->getTok(); if (!is_null($this->token)) { return $this->raiseError('Unexpected token'); } return $tree; break; case 'index': $tree = array('command' => 'drop_index'); break; case 'constraint': $tree = array('command' => 'drop_constraint'); break; case 'sequence': $tree = array('command' => 'drop_sequence'); break; default: return $this->raiseError('Unknown object to drop'); } return $tree; } // }}}
// {{{ parseSelect() function parseSelect($subSelect = false) { $tree = array('command' => 'select'); $this->getTok(); if (($this->token == 'distinct') || ($this->token == 'all')) { $tree['set_quantifier'] = $this->token; $this->getTok(); } if ($this->token == '*') { $tree['column_names'][] = '*'; $this->getTok(); } elseif ($this->token == 'ident' || $this->isFunc()) { while ($this->token != 'from') { if ($this->token == 'ident') { $prevTok = $this->token; $prevTokText = $this->lexer->tokText; $this->getTok(); if ($this->token == '.') { $columnTable = $prevTokText; $this->getTok(); $prevTok = $this->token; $prevTokText = $this->lexer->tokText; } else { $columnTable = ''; }
if ($prevTok == 'ident') { $columnName = $prevTokText; } else { return $this->raiseError('Expected column name'); }
if ($this->token == 'as') { $this->getTok(); if ($this->token == 'ident' ) { $columnAlias = $this->lexer->tokText; } else { return $this->raiseError('Expected column alias'); } } elseif ($this->token == 'ident') { $columnAlias = $this->lexer->tokText; } else { $columnAlias = ''; }
$tree['column_tables'][] = $columnTable; $tree['column_names'][] = $columnName; $tree['column_aliases'][] = $columnAlias; if ($this->token != 'from') { $this->getTok(); } if ($this->token == ',') { $this->getTok(); } } elseif ($this->isFunc()) { if (!isset($tree['set_quantifier'])) { $result = $this->parseFunctionOpts(); if (PEAR::isError($result)) { return $result; } $tree['set_function'][] = $result; $this->getTok();
if ($this->token == 'as') { $this->getTok(); if ($this->token == 'ident' ) { $columnAlias = $this->lexer->tokText; } else { return $this->raiseError('Expected column alias'); } } else { $columnAlias = ''; } } else { return $this->raiseError('Cannot use "'. $tree['set_quantifier'].'" with '.$this->token); } } elseif ($this->token == ',') { $this->getTok(); } else { return $this->raiseError('Unexpected token "'.$this->token.'"'); } } } else { return $this->raiseError('Expected columns or a set function'); } if ($this->token != 'from') { return $this->raiseError('Expected "from"'); } $this->getTok(); while ($this->token == 'ident') { $tree['table_names'][] = $this->lexer->tokText; $this->getTok(); if ($this->token == 'ident') { $tree['table_aliases'][] = $this->lexer->tokText; $this->getTok(); } elseif ($this->token == 'as') { $this->getTok(); if ($this->token == 'ident') { $tree['table_aliases'][] = $this->lexer->tokText; } else { return $this->raiseError('Expected table alias'); } $this->getTok(); } else { $tree['table_aliases'][] = ''; } if ($this->token == 'on') { $clause = $this->parseSearchClause(); if (PEAR::isError($clause)) { return $clause; } $tree['table_join_clause'][] = $clause; } else { $tree['table_join_clause'][] = ''; } if ($this->token == ',') { $tree['table_join'][] = ','; $this->getTok(); } elseif ($this->token == 'join') { $tree['table_join'][] = 'join'; $this->getTok(); } elseif (($this->token == 'cross') || ($this->token == 'inner')) { $join = $this->lexer->tokText; $this->getTok(); if ($this->token != 'join') { return $this->raiseError('Expected token "join"'); } $tree['table_join'][] = $join.' join'; $this->getTok(); } elseif (($this->token == 'left') || ($this->token == 'right')) { $join = $this->lexer->tokText; $this->getTok(); if ($this->token == 'join') { $tree['table_join'][] = $join.' join'; } elseif ($this->token == 'outer') { $join .= ' outer'; $this->getTok(); if ($this->token == 'join') { $tree['table_join'][] = $join.' join'; } else { return $this->raiseError('Expected token "join"'); } } else { return $this->raiseError('Expected token "outer" or "join"'); } $this->getTok(); } elseif ($this->token == 'natural') { $join = $this->lexer->tokText; $this->getTok(); if ($this->token == 'join') { $tree['table_join'][] = $join.' join'; } elseif (($this->token == 'left') || ($this->token == 'right')) { $join .= ' '.$this->token; $this->getTok(); if ($this->token == 'join') { $tree['table_join'][] = $join.' join'; } elseif ($this->token == 'outer') { $join .= ' '.$this->token; $this->getTok(); if ($this->token == 'join') { $tree['table_join'][] = $join.' join'; } else { return $this->raiseError('Expected token "join" or "outer"'); } } else { return $this->raiseError('Expected token "join" or "outer"'); } } else { return $this->raiseError('Expected token "left", "right" or "join"'); } $this->getTok(); } elseif (($this->token == 'where') || ($this->token == 'order') || ($this->token == 'limit') || (is_null($this->token))) { break; } } while (!is_null($this->token) && (!$subSelect || $this->token != ')') && $this->token != ')') { switch ($this->token) { case 'where': $clause = $this->parseSearchClause(); if (PEAR::isError($clause)) { return $clause; } $tree['where_clause'] = $clause; break; case 'order': $this->getTok(); if ($this->token != 'by') { return $this->raiseError('Expected "by"'); } $this->getTok(); while ($this->token == 'ident') { $col = $this->lexer->tokText; $this->getTok(); if (isset($this->synonyms[$this->token])) { $order = $this->synonyms[$this->token]; if (($order != 'asc') && ($order != 'desc')) { return $this->raiseError('Unexpected token'); } $this->getTok(); } else { $order = 'asc'; } if ($this->token == ',') { $this->getTok(); } $tree['sort_order'][$col] = $order; } break; case 'limit': $this->getTok(); if ($this->token != 'int_val') { return $this->raiseError('Expected an integer value'); } $length = $this->lexer->tokText; $start = 0; $this->getTok(); if ($this->token == ',') { $this->getTok(); if ($this->token != 'int_val') { return $this->raiseError('Expected an integer value'); } $start = $length; $length = $this->lexer->tokText; $this->getTok(); } $tree['limit_clause'] = array('start'=>$start, 'length'=>$length); break; case 'group': $this->getTok(); if ($this->token != 'by') { return $this->raiseError('Expected "by"'); } $this->getTok(); while ($this->token == 'ident') { $col = $this->lexer->tokText; $this->getTok(); if ($this->token == ',') { $this->getTok(); } $tree['group_by'][] = $col; } break; default: return $this->raiseError('Unexpected clause'); } } return $tree; } // }}}
// {{{ parse($string) function parse($string = null) { if (is_string($string)) { // Initialize the Lexer with a 3-level look-back buffer $this->lexer = new Lexer($string, 3); $this->lexer->symbols =& $this->symbols; } else { if (!is_object($this->lexer)) { return $this->raiseError('No initial string specified'); } }
// get query action $this->getTok(); switch ($this->token) { case null: // null == end of string return $this->raiseError('Nothing to do'); case 'select': return $this->parseSelect(); case 'update': return $this->parseUpdate(); case 'insert': return $this->parseInsert(); case 'delete': return $this->parseDelete(); case 'create': return $this->parseCreate(); case 'drop': return $this->parseDrop(); default: return $this->raiseError('Unknown action :'.$this->token); } } // }}} } ?>
|