/// <summary> /// Visits an aggregation node. /// Creates a new aggregation function based on the provided name. /// And initilises parsing of the aggregation argument. /// </summary> public void Visit(AggregateFuncNode node) { Aggregate aggregate = null; Type aggType = null; if (node.next == null) { throw new ArgumentException($"{this.GetType()}, exprected aggregation arguments."); } else { // count(*) if (node.next.GetType() == typeof(IdentifierNode)) { if (node.funcName.ToLower() == "count" && ((IdentifierNode)node.next).value == "*") { aggregate = Aggregate.Factory("count", typeof(int), null); aggType = typeof(int); } else { throw new ArgumentException($"{this.GetType()}, expected count(*)."); } } else { // Every other aggregation. // The only possibility is that the next node is VariableNode. // So the argument will be created in this.Expr, from this expr the holder must be created. // After the holder is created the aggregation is created with the expression. // After this process, the expression that will be returned is created -> aggregation reference. node.next.Accept(this); var tmpHolder = new ExpressionHolder(this.expr); aggregate = Aggregate.Factory(node.funcName.ToLower(), tmpHolder.ExpressionType, tmpHolder); aggType = tmpHolder.ExpressionType; } } // Rewrite the expression used for aggregation argument to aggregation reference. int aggPos = this.exprInfo.AddAggregate(aggregate); if (node.funcName.ToLower() == "avg") { this.expr = AggregateReferenceFactory.Create(typeof(double), aggPos, this.exprInfo.GroupByhashExprs.Count, this.exprInfo.Aggregates[aggPos]); } else if (node.funcName.ToLower() == "count") { this.expr = AggregateReferenceFactory.Create(typeof(int), aggPos, this.exprInfo.GroupByhashExprs.Count, this.exprInfo.Aggregates[aggPos]); } else if (node.funcName.ToLower() == "sum") { this.expr = AggregateReferenceFactory.Create(typeof(long), aggPos, this.exprInfo.GroupByhashExprs.Count, this.exprInfo.Aggregates[aggPos]); } else { this.expr = AggregateReferenceFactory.Create(aggType, aggPos, this.exprInfo.GroupByhashExprs.Count, this.exprInfo.Aggregates[aggPos]); } }
/// <summary> /// AggregateFunc -> IDENTIFIER \( VarReference \) /// </summary> /// <param name="tokens"> Tokens to parse. </param> /// <param name="position"> A position of a token. </param> /// <returns> A non empty aggregate node. </returns> static private Node ParseAggregateFunc(ref int position, List <Token> tokens) { // FuncName ( if (!((CheckToken(position, Token.TokenType.Identifier, tokens)) && (CheckToken(position + 1, Token.TokenType.LeftParen, tokens)))) { return(null); } else { AggregateFuncNode aggregate = new AggregateFuncNode(); // Save the name of the function. aggregate.funcName = tokens[position].strValue; // It must inc by 2 because it was +1 moves it to left parent and another +1 moves it to next token. position += 2; if (CheckToken(position, Token.TokenType.Asterix, tokens)) { if (aggregate.funcName.ToLower() != "count") { ThrowError("Expression parser", "Cannot call other aggregate functions with * except count.", position, tokens); } else { aggregate.next = new IdentifierNode("*"); position++; } } else { aggregate.next = ParseVarReference(ref position, tokens); } // ) if (!CheckToken(position, Token.TokenType.RightParen, tokens)) { ThrowError("Expression parser", "Expected ) .", position, tokens); } else { position++; } return(aggregate); } }
public void Visit(AggregateFuncNode node) { throw new NotImplementedException(); }