Skip to content

Commit

Permalink
fixed bug #4035
Browse files Browse the repository at this point in the history
git-svn-id: http://svn.php.net/repository/pear/packages/SQL_Parser/trunk@263297 c90b9560-bf6c-de11-be94-00142212c4b1
  • Loading branch information
Sebastian Mendel committed Jul 23, 2008
1 parent fc2398d commit 2672903
Show file tree
Hide file tree
Showing 4 changed files with 318 additions and 55 deletions.
234 changes: 181 additions & 53 deletions Parser.php
Original file line number Diff line number Diff line change
Expand Up @@ -1229,55 +1229,165 @@ public function parseInsert()
*/
public function parseUpdate()
{
$this->getTok();
if ($this->token != 'ident') {
return $this->raiseError('Expected table name, found: ' . $this->token);
}
$tree = array('command' => 'update');
$tree['table_names'][] = $this->lexer->tokText;

$this->getTok();
$tree['tables'][] = $this->parseIdentifier('table');

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();
$tree['columns'][] = $this->parseIdentifier();

if ($this->token != '=') {
return $this->raiseError('Expected =');
}

$this->getTok();
if ($this->isVal($this->token) || $this->token == 'ident') {
if ($this->isVal($this->token)) {
$tree['values'][] = array(
'value' => $this->lexer->tokText,
'type' => $this->token,
);
$this->getTok();
} elseif ($this->token == 'ident') {
$tree['values'][] = array(
'value' => $this->parseIdentifier(),
'type' => 'ident',
);
} else {
$this->getParams($values, $types);
$tree['values'][] = array(
'value' => $values[0],
'type' => $types[0],
);
$this->getTok();
}

if ($this->token != ',') {
break;
}
}

if ($this->token == 'from') {
$this->getTok();
$tree['from'] = $this->parseFrom();
}

if ($this->token == 'where') {
$clause = $this->parseSearchClause();
if (false === $clause) {
return $clause;
}
$tree['where_clause'] = $clause;
}

return $tree;
}
// }}}

public function parseFrom()
{
$tree = array();

while ($this->token == 'ident') {
$tree['table_names'][] = $this->lexer->tokText;
$this->getTok();
if ($this->token == 'where') {
if ($this->token == 'ident') {
$tree['table_aliases'][] = $this->lexer->tokText;
$this->getTok();
} elseif ($this->token == 'as') {
$this->getTok();
if ($this->token != 'ident') {
return $this->raiseError('Expected table alias');
}
$tree['table_aliases'][] = $this->lexer->tokText;
$this->getTok();
} else {
$tree['table_aliases'][] = '';
}
if ($this->token == 'on') {
$clause = $this->parseSearchClause();
if (false === $clause) {
return $clause;
}
$tree['where_clause'] = $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') {
// (CROSS|INNER) JOIN
$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') {
// (LEFT|RIGHT) OUTER? JOIN
$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') {
return $this->raiseError('Expected token "join"');
}
$tree['table_join'][] = $join.' join';
} else {
return $this->raiseError('Expected token "outer" or "join"');
}
$this->getTok();
} elseif ($this->token == 'natural') {
// NATURAL ((LEFT|RIGHT) OUTER?)? JOIN
$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;
} elseif ($this->token != ',') {
return $this->raiseError('Expected "where" or ","');
}
}

return $tree;
}
// }}}

// {{{ parseDelete()
/**
Expand Down Expand Up @@ -1362,6 +1472,58 @@ public function parseDrop()
}
// }}}

public function parseIdentifier($type = 'column')
{
$ident = array(
'database' => '',
'table' => '',
'column' => '',
'alias' => '',
);

$ident['column'] = $this->lexer->tokText;
$prevTok = $this->token;

$this->getTok();
if ($this->token == '.') {
$this->getTok();
$prevTok = $this->token;
$ident['table'] = $ident['column'];
$ident['column'] = $this->lexer->tokText;
$this->getTok();
if ($this->token == '.') {
$this->getTok();
$prevTok = $this->token;
$ident['database'] = $ident['table'];
$ident['table'] = $ident['column'];
$ident['column'] = $this->lexer->tokText;
$this->getTok();
}
}

if ($prevTok != 'ident' && $prevTok != '*') {
return $this->raiseError('Expected name, found: ' . $prevTok);
}

if ($type === 'table') {
$ident['database'] = $ident['table'];
$ident['table'] = $ident['column'];
unset($ident['column']);
}

if ($this->token == 'as') {
$this->getTok();
if ($this->token != 'ident' ) {
return $this->raiseError('Expected column alias');
}
$ident['alias'] = $this->lexer->tokText;
} elseif ($this->token == 'ident') {
$ident['alias'] = $this->lexer->tokText;
}

return $ident;
}

// {{{ parseSelect()
/**
* @access public
Expand All @@ -1386,48 +1548,14 @@ public function parseSelect($subSelect = false)
*/

while ($this->token != 'from' && $this->token != null) {
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' && $this->token != '*') {
return $this->raiseError('Expected column name');
}
$columnName = $prevTokText;

if ($this->token == 'as') {
$this->getTok();
if ($this->token != 'ident' ) {
return $this->raiseError('Expected column alias');
}
$columnAlias = $this->lexer->tokText;
} else {
$columnAlias = '';
}

$tree['column_tables'][] = $columnTable;
$tree['column_names'][] = $columnName;
$tree['column_aliases'][] = $columnAlias;
if ($this->token == 'ident' || $this->token == '*') {
$tree['fields'][] = $this->parseIdentifier();
if ($this->token != 'from') {
$this->getTok();
}
if ($this->token == ',') {
$this->getTok();
}
} elseif ($this->token == '*') {
$tree['column_names'][] = '*';
$tree['column_tables'][] = '';
$tree['column_aliases'][] = '';
$this->getTok();
} elseif ($this->isFunc()) {
if (! isset($tree['set_quantifier'])) {
$result = $this->parseFunctionOpts();
Expand Down
4 changes: 2 additions & 2 deletions Parser/Lexer.php
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,7 @@ function nextToken()
break;
}
}

if (isset($this->quotes[$c])) {
$quote = $c;
$state = 12;
Expand Down Expand Up @@ -277,7 +277,7 @@ function nextToken()
}
}


// comments
foreach ($this->comments as $comment_start => $comment_end) {
if (substr($this->string, $this->tokPtr - 1, strlen($comment_start)) === $comment_start) {
Expand Down
10 changes: 10 additions & 0 deletions tests/sql/bug#4035.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
-- SQL_PARSER_FLAG_MYSQL
UPDATE tblTicklerPatientData
SET tblTicklerPatientData.final_diagnosis = ptc.path_diagnosis_codes
FROM
tblTicklerPatientData
INNER JOIN `PatientTest(Case)` as ptc
ON tblTicklerPatientData.PatientTest_key = ptc.PatientTest_key
WHERE
ptc.path_diagnosis_codes Is Not Null
and tblTicklerPatientData.final_diagnosis is null';
Loading

0 comments on commit 2672903

Please sign in to comment.