Location: PHPKode > scripts > SQL Parse and Compile > sql-parse-and-compile/Sql_Parser/Sql_ParserFunction.class.php
<?php

/**
 *
 * Sql_ParserFunction
 * @package Sql
 * @subpackage Sql_Compiler
 * @author Thomas Sch&#65533;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);    	
    }
    
}

Return current item: SQL Parse and Compile