<?php
/**
*
* Sql_ParserFunction
* @package Sql
* @subpackage Sql_Compiler
* @author Thomas Sch�fer
* @since 30.11.2008 07:49:30
* @desc parses a sql function into array
*/
class Sql_ParserFunction {
const BITSHIFT = "<<";
public static function doParse($recursing=false)
{
$opts = array();
$function = strtoupper( Sql_Object::token() );
$opts['Name'] = $function;
Sql_Parser::getTok();
if (Sql_Object::token() != Sql_Parser::OPENBRACE)
{
return Sql_Parser::raiseError('Expected "("', __LINE__);
}
switch (strtolower( $function ) )
{
// single argument functions
case 'bit_count':
case 'bit_or':
case 'bit_and':
case "pi":
case 'abs':
case 'acos':
case 'asin':
case 'ceil':
case 'ceiling':
case 'cos':
case 'cot':
case 'crc32':
case 'degrees':
case 'exp':
case 'floor':
case 'format':
case 'ln':
case 'max':
case 'min':
case 'log':
case 'log2':
case 'log10':
case 'radians':
case 'rand':
case 'round':
case 'sign':
case 'sin':
case 'sqrt':
case 'tan':
$opts = self::processSingle($opts, "int_val");
if(isset($opts["error"])) {
return $opts["result"];
}
break;
// string functions
case 'ascii':
case 'bin':
case 'bit_length':
case 'char_length':
case 'character_length':
case 'lcase':
case 'length':
case 'lower':
case 'ltrim':
case 'oct':
case 'octet_length':
case 'ord':
case 'quote':
case "rand":
case 'reverse':
case 'rtrim':
case 'soundex':
case 'space':
case 'ucase':
case 'unhex':
case 'upper':
$opts = self::processSingle($opts, "text_val");
if(isset($opts["error"])) {
return $opts["result"];
}
break;
// double argument functions
case 'atan':
case 'atan2':
case 'pow':
case 'power':
case 'round':
case 'truncate':
case 'find_in_set':
case 'format':
case 'instr':
case 'left':
case 'locate':
case 'repeat':
case 'right':
case 'substr':
case 'substring':
$opts = self::processDouble($opts);
if(isset($opts["error"])) {
return $opts["result"];
}
break;
// special argument function => distinctive
case 'count':
$opts = self::processDistinctive($opts);
if(isset($opts["error"])) {
return $opts["result"];
}
break;
// infinite argument functions
case 'concat':
case 'concat_ws':
case 'make_set':
case 'elt':
$opts = self::processInfinite($opts);
if(isset($opts["error"])) {
return $opts["result"];
}
break;
default:
// other
Sql_Parser::getTok();
$opts['Arg'] = Sql_Object::lexer()->tokText;
break;
}
Sql_Parser::getTok();
if (Sql_Object::token() != Sql_Parser::CLOSEBRACE)
{
// works for single bit shifted functions
if(Sql_Object::token()==self::BITSHIFT) {
$opts['Arg']["Left"]["Value"] = $opts['Arg'][0];
$opts['Arg']["Left"]["Type"] = "int_val";
unset($opts['Arg'][0]);
$opts['Arg']["Op"] = '<<';
Sql_Parser::getTok();
$opts['Arg']["Right"]["Value"] = Sql_Object::token();
$opts['Arg']["Right"]["Type"] = "ident";
$opts['process'] = "text_val";
Sql_Parser::getTok();
} else {
return Sql_Parser::raiseError('Expected ")"', __LINE__);
}
}
if(empty($recursing))
{
$opts = Sql_Parser::processAlias($opts);
}
return $opts;
}
private static function processInfinite($opts) {
Sql_Parser::getTok();
$increment=0;
while (Sql_Object::token() != Sql_Parser::CLOSEBRACE)
{
switch (Sql_Object::token())
{
case 'ident':
$opts['Arg'][$increment]["Value"] = Sql_Object::lexer()->tokText;
$opts['Arg'][$increment]["Type"] = Sql_Object::token();
break;
case 'text_val':
$opts['Arg'][$increment]["Value"] = '"'.Sql_Object::lexer()->tokText.'"';
$opts['Arg'][$increment]["Type"] = Sql_Object::token();
break;
case 'real_val':
case 'int_val':
$opts['Arg'][$increment]["Value"] = Sql_Object::lexer()->tokText;
$opts['Arg'][$increment]["Type"] = Sql_Object::token();
break;
case ',':
// do nothing
$increment++;
break;
default:
return array("error" => true, "result" => Sql_Parser::raiseError('Expected a string or a column name', __LINE__));
}
Sql_Parser::getTok();
}
Sql_Object::lexer()->pushBack();
return $opts;
}
private static function processDistinctive($opts){
Sql_Parser::getTok();
$increment=0;
switch (Sql_Object::token())
{
case 'distinct':
$opts['Distinct'] = true;
Sql_Parser::getTok();
if (Sql_Object::token() != 'ident')
{
return array("error" => true, "result" => Sql_Parser::raiseError('Expected a column name', __LINE__));
}
case 'ident':
case '*':
$opts['Arg'][$increment]["Value"] = Sql_Object::lexer()->tokText;
$opts['Arg'][$increment]["Type"] = Sql_Object::token();
break;
default:
return array("error" => true, "result" => Sql_Parser::raiseError('Invalid argument', __LINE__));
}
return $opts;
}
/**
* processEmpty
* @desc processes sql functions which have no argument
* @return opts
*/
private static function processEmpty($opts){
Sql_Parser::getTok();
if(Sql_Object::token()==Sql_Parser::CLOSEBRACE) {
$opts['Arg'] = false;
Sql_Object::lexer()->pushBack();
} else {
return array("error" => true, "result" => Sql_Parser::raiseError('Invalid argument', __LINE__));
}
return $opts;
}
/**
* processSingle
* @desc single argument sql function
* @param array $opts option data of sql function part
* @return array
*/
private static function processSingle($opts){
Sql_Parser::getTok();
if(Sql_Object::token()!=Sql_Parser::CLOSEBRACE)
{
if(Sql_Parser::isFunc()) {
$opts['Arg'][]['Function'][0] = self::doParse(true);
} else {
switch (Sql_Object::token())
{
case 'ident':
case 'int_val':
case 'real_val':
$opts['Arg'][] = Sql_Object::lexer()->tokText;
break;
case 'text_val':
$opts['Arg'][] = '"'. Sql_Object::lexer()->tokText.'"';
break;
default:
return array("error" => true, "result" => Sql_Parser::raiseError('Invalid argument', __LINE__));
}
}
} else {
$opts["Arg"] = false;
Sql_Object::lexer()->pushBack();
}
return $opts;
}
/**
* processDouble
* @desc double argument sql function
* @param array $opts option data of sql function part
* @param string $prcType int_val, text_val, real_val
* @return array
*/
private static function processDouble($opts, $prcType="text_val"){
Sql_Parser::getTok();
$increment = 0;
while (Sql_Object::token() != Sql_Parser::CLOSEBRACE) {
$position = ($increment==0) ? "Left" : "Right";
switch (Sql_Object::token())
{
case Sql_Parser::isControlFlowFunction():
$recurseOpts = array();
$recurseOpts['Function'] = Sql_ParserFlow::parse(true);
$opts['Arg'][$position]["Value"] = $recurseOpts;
$opts['Arg'][$position]["Type"] = "Flowcontrol";
break;
case Sql_Parser::isFunc():
$recurseOpts = array();
$recurseOpts['Function'] = Sql_ParserFunction::parse(true);
$opts['Arg'][$position]["Value"] = $recurseOpts;
$opts['Arg'][$position]["Type"] = "Function";
break;
case 'ident':
case 'int_val':
case 'real_val':
$opts['Arg'][$position]["Value"] = Sql_Object::lexer()->tokText;
$opts['Arg'][$position]["Type"] = Sql_Object::token();
break;
case ',':
$increment++;
break;
case 'text_val':
$opts['Arg'][$position]["Value"] = '"'. Sql_Object::lexer()->tokText.'"';
$opts['Arg'][$position]["Type"] = Sql_Object::token();
break;
default:
$errString = 'Invalid argument for '. $prcType." process";
return array("error" => true, "result" => Sql_Parser::raiseError($errString, __LINE__));
}
Sql_Parser::getTok();
}
Sql_Object::lexer()->pushBack();
return $opts;
}
public function parse($recursing=false){
return self::doParse($recursing);
}
}
|