private ResultSetBuilder VisitContains(SymbolContainsExpression exp) { var memberName = ExHelper.GetMemberName(exp.Match, _itemType, exp); var result = new ResultSetBuilder(_journal, _tx); var vals = ExHelper.GetLiteralValue(exp.Values, _parameters, exp); if (!(vals is IEnumerable)) { throw QueryExceptionExtensions.ExpressionNotSupported( string.Format("Parameter {0} does not implement IEnumerable.", exp.Values), exp); } try { result.IndexCollectionScan(memberName, (IEnumerable)vals, exp); } catch (InvalidCastException ex) { throw QueryExceptionExtensions.ExpressionNotSupported( string.Format("Parameter {0} value of type '{1}' cannot be used in " + "IN statement with column '{2}'. {3}", exp.Values, vals.GetType(), memberName, ex.Message), exp); } return(result); }
public void ApplyMap(List <ColumnNameExpression> columns) { _columns = new List <string>(columns.Count); foreach (var columnExp in columns) { var col = Metadata.Columns.FirstOrDefault(c => string.Equals(c.PropertyName, columnExp.Name, StringComparison.OrdinalIgnoreCase)); if (col == null) { throw QueryExceptionExtensions.ExpressionNotSupported( "Column [{0}] does not exists in journal " + Metadata.Name, columnExp); } _columns.Add(col.PropertyName); } }
private ResultSetBuilder VisitConstant(ConstantExpression exp) { var expType = exp.Value.GetType(); if (expType.GetInterfaces().Any(x => x.IsGenericType && x.GetGenericTypeDefinition() == typeof(IQueryable <>) && x.GetGenericArguments()[0] == _itemType)) { return(new ResultSetBuilder(_journal, _tx)); } throw QueryExceptionExtensions.ExpressionNotSupported( "Expression {0} cannot be bound to Journal operation.", exp); }
private ResultSetBuilder VisitLatestBy(LatestBySymbolExpression exp) { try { var result = exp.Body != null?Visit(exp.Body) : new ResultSetBuilder(_journal, _tx); result.TakeLatestBy(exp.LatestBy); return(result); } catch (NFSdbQueryableNotSupportedException ex) { throw QueryExceptionExtensions.ExpressionNotSupported(ex.Message, exp); } }
private ResultSetBuilder VisitFilter(FilterExpression exp) { var source = Visit(exp.Source); if (!source.CanApplyFilter()) { throw QueryExceptionExtensions.ExpressionNotSupported( "Where cannot be applied after Take, Skip, Single, First or Count expressions.", exp); } var filter = Visit(exp.Filter); source.ApplyFilter(filter); return(source); }
public void IndexCollectionScan(string memberName, IEnumerable values, Expression exp) { var p = new RowScanPlanItem(_journal, _tx); var column = Metadata.GetColumnByPropertyName(memberName); switch (column.DataType.ColumnType) { case EFieldType.Byte: p.AddContainsScan(column, ToIList <byte>(values)); break; case EFieldType.Bool: p.AddContainsScan(column, ToIList <bool>(values)); break; case EFieldType.Int16: p.AddContainsScan(column, ToIList <short>(values)); break; case EFieldType.Int32: p.AddContainsScan(column, ToIList <int>(values)); break; case EFieldType.Int64: p.AddContainsScan(column, ToIList <long>(values)); break; case EFieldType.Double: p.AddContainsScan(column, ToIList <double>(values)); break; case EFieldType.Symbol: case EFieldType.String: p.AddContainsScan(column, ToIList <string>(values)); break; case EFieldType.DateTime: case EFieldType.DateTimeEpochMs: p.AddContainsScan(column, ToIList <DateTime>(values)); break; default: throw QueryExceptionExtensions.ExpressionNotSupported( string.Format("Column of type {0} cannot be bound to Contains expressions", column.DataType.ColumnType), exp); } _planHead = p; }
public override object Execute(Expression expression) { var lambda = expression as LambdaExpression; if (lambda == null && _cache != null && expression.NodeType != ExpressionType.Constant) { return(_cache.Execute(expression)); } var result = GetExecutionPlan(expression); var res = result.Build(); if (res.IsSingle) { var rowID = res.RowID; // First / Last OrDefault can return null. if (rowID == 0) { return(null); } int partitionID = RowIDUtil.ToPartitionIndex(rowID); var lastPartitionReader = _tx.Read(partitionID); long localRowID = RowIDUtil.ToLocalRowID(rowID); // ReSharper disable once PossibleNullReferenceException return(lastPartitionReader.Read <T>(localRowID, _tx.ReadCache)); } switch (res.PostExpression) { case EJournalExpressionType.None: return(new ResultSet <T>(res.Rowids, _tx)); case EJournalExpressionType.LongCount: return(res.Rowids.LongCount()); case EJournalExpressionType.Count: return(res.Rowids.Count()); default: throw QueryExceptionExtensions.ExpressionNotSupported( string.Format("Post expression {0} is not supported at this level", res.PostExpression), expression); } }
public static string GetMemberName(Expression expression, Type journalType, Expression parentExpression) { var ex = expression as MemberExpression; if (ex != null) { var memEx = ex; return(GetMemberName(memEx, journalType)); } var match = expression as ColumnNameExpression; if (match != null) { return(match.Name); } throw QueryExceptionExtensions.ExpressionNotSupported("Cannot extract column name from expression ", parentExpression); }
public static object GetLiteralValue(Expression literalExpression, IEnumerable <QlParameter> parameters, Expression parentExpression) { var valExp = literalExpression as ValueListExpression; if (valExp != null) { return(valExp.Values.Select(v => GetLiteralValue(v, parameters, parentExpression)).ToList()); } if (literalExpression is LiteralExpression) { literalExpression = ((LiteralExpression)literalExpression).Constant; } else { var exp = literalExpression as ParameterNameExpression; if (exp != null) { var paramExp = exp; QlParameter p; if (parameters == null || (p = parameters.FirstOrDefault( pp => string.Equals(pp.Name, paramExp.Name, StringComparison.OrdinalIgnoreCase))) == null) { throw QueryExceptionExtensions.ExpressionNotSupported( "Unable to evaluate <{0}>. Parameter value not passed.", parentExpression); } return(p.Value); } } if (!(literalExpression is ConstantExpression)) { throw QueryExceptionExtensions.ExpressionNotSupported( "Unable to evaluate <{0}>. Expressions of type column = " + "'literal' are supported only.", parentExpression); } var memEx = (ConstantExpression)literalExpression; return(memEx.Value); }
private Expression BindWhere(Type resultType, Expression source, LambdaExpression predicate) { if (resultType != typeof(IQueryable <T>)) { throw QueryExceptionExtensions.ExpressionNotSupported( "Usage of expressions in select statment is not allowed." + " Please convert to IEnumerable and perform select statement.", source); } var where = Visit(predicate.Body); if (source is ConstantExpression) { return(where); } source = Visit(source); if (!(source is FilterExpression) && !(source is PostResultExpression)) { return(new IntersectExpression(source, where)); } return(new FilterExpression(where, source)); }
private ResultSetBuilder VisitOrderBy(OrderExpression exp) { var result = Visit(exp.Body); var predicate = exp.Predicate; var lambda = predicate as LambdaExpression; if (lambda != null) { predicate = lambda.Body; } var member = ExHelper.GetMemberName(predicate, _itemType, exp); var column = _journal.Metadata.TryGetColumnByPropertyName(member); if (column == null) { throw QueryExceptionExtensions.ExpressionNotSupported( string.Format("Column '{0}' does not exist", member), exp); } result.ApplyOrderBy(column, (EJournalExpressionType)exp.NodeType); return(result); }
public static string GetMemberName(Expression expression, Type journalType) { ExpressionType leftType = expression.GetLeft().NodeType; var member = leftType == ExpressionType.MemberAccess || leftType == (ExpressionType)EJournalExpressionType.Column ? expression.GetLeft() : expression.GetRight(); var ex = member as MemberExpression; if (ex != null) { var memEx = ex; return(GetMemberName(memEx, journalType)); } var match = member as ColumnNameExpression; if (match != null) { return(match.Name); } throw QueryExceptionExtensions.ExpressionNotSupported("Cannot extract column name from expression ", expression); }
public ResultSetBuilder Visit(Expression exp) { if (exp == null) { return(null); } switch (exp.NodeType) { case ExpressionType.Negate: case ExpressionType.NegateChecked: case ExpressionType.Not: case ExpressionType.Convert: case ExpressionType.ConvertChecked: case ExpressionType.ArrayLength: case ExpressionType.Quote: case ExpressionType.TypeAs: case ExpressionType.UnaryPlus: return(VisitUnary((UnaryExpression)exp)); case ExpressionType.Add: case ExpressionType.AddChecked: case ExpressionType.Subtract: case ExpressionType.SubtractChecked: case ExpressionType.Multiply: case ExpressionType.MultiplyChecked: case ExpressionType.Divide: case ExpressionType.Modulo: case ExpressionType.And: case ExpressionType.AndAlso: case ExpressionType.Or: case ExpressionType.OrElse: case ExpressionType.LessThan: case ExpressionType.LessThanOrEqual: case ExpressionType.GreaterThan: case ExpressionType.GreaterThanOrEqual: case ExpressionType.Equal: case ExpressionType.NotEqual: case ExpressionType.Coalesce: case ExpressionType.ArrayIndex: case ExpressionType.RightShift: case ExpressionType.LeftShift: case ExpressionType.ExclusiveOr: case ExpressionType.Power: return(VisitBinary(exp)); case ExpressionType.Constant: return(VisitConstant((ConstantExpression)exp)); } switch ((EJournalExpressionType)exp.NodeType) { case EJournalExpressionType.Contains: return(VisitContains((SymbolContainsExpression)exp)); case EJournalExpressionType.Single: case EJournalExpressionType.Count: case EJournalExpressionType.LongCount: case EJournalExpressionType.Reverse: case EJournalExpressionType.First: case EJournalExpressionType.FirstOrDefault: case EJournalExpressionType.Last: case EJournalExpressionType.LastOrDefault: return(VisitCall((PostResultExpression)exp)); case EJournalExpressionType.OrderBy: case EJournalExpressionType.OrderByDescending: return(VisitOrderBy((OrderExpression)exp)); case EJournalExpressionType.Take: case EJournalExpressionType.Skip: return(VisitCall((SliceExpression)exp)); case EJournalExpressionType.Map: return(VisitCall((MapExpression)exp)); case EJournalExpressionType.LatestBy: return(VisitLatestBy((LatestBySymbolExpression)exp)); case EJournalExpressionType.Intersect: var intsct = (IntersectExpression)exp; return(VisitSet(intsct.Left, intsct.Right, ExpressionType.And)); case EJournalExpressionType.Union: var union = (UnionExpression)exp; return(VisitSet(union.Left, union.Right, ExpressionType.Or)); case EJournalExpressionType.Filter: return(VisitFilter((FilterExpression)exp)); case EJournalExpressionType.Journal: return(new ResultSetBuilder(_journal, _tx)); default: throw QueryExceptionExtensions.ExpressionNotSupported( "Expression {0} cannot be bound to Journal operation.", exp); } }
private ResultSetBuilder EvaluateEquals(Expression expression) { if (expression.NodeType == ExpressionType.Equal || expression.NodeType == ExpressionType.NotEqual) { var literal = ExHelper.GetLiteralValue(expression, _parameters); var memberName = ExHelper.GetMemberName(expression, _itemType); IColumnMetadata column; try { column = _journal.Metadata.GetColumnByPropertyName(memberName); } catch (NFSdbConfigurationException) { throw QueryExceptionExtensions.ExpressionNotSupported( string.Format("Column {0} does not exist", memberName), expression); } if (_journal.Metadata.TimestampColumnID == column.ColumnID) { if (expression.NodeType == ExpressionType.Equal) { if (literal is long || literal is DateTime) { if (GetTimestamp(_journal.Metadata) != null && GetTimestamp(_journal.Metadata).PropertyName == memberName) { DateInterval filterInterval; if (literal is long) { var timestamp = (long)literal; filterInterval = new DateInterval(DateUtils.UnixTimestampToDateTime(timestamp), DateUtils.UnixTimestampToDateTime(timestamp + 1)); } else { var timestamp = (DateTime)literal; filterInterval = new DateInterval(timestamp, new DateTime(timestamp.Ticks + 1, timestamp.Kind)); } var result = new ResultSetBuilder(_journal, _tx); result.TimestampInterval(filterInterval); return(result); } } } } var res = new ResultSetBuilder(_journal, _tx); try { if (literal != null) { if (expression.NodeType == ExpressionType.Equal) { ReflectionHelper.CallStaticPrivateGeneric("CreateColumnScan", this, column.DataType.Clazz, column, literal, res); } else if (expression.NodeType == ExpressionType.NotEqual) { ReflectionHelper.CallStaticPrivateGeneric("CreateColumnNotEqualScan", this, column.DataType.Clazz, column, literal, res); } } else { if (expression.NodeType == ExpressionType.Equal) { ReflectionHelper.CallStaticPrivateGeneric("CreateColumnScan", this, column.DataType.Clazz, column, null, res); } else if (expression.NodeType == ExpressionType.NotEqual) { ReflectionHelper.CallStaticPrivateGeneric("CreateColumnNotEqualScan", this, column.DataType.Clazz, column, null, res); } } } catch (NFSdbQueryableNotSupportedException ex) { throw QueryExceptionExtensions.ExpressionNotSupported(ex.Message, expression); } catch (InvalidCastException ex) { throw QueryExceptionExtensions.ExpressionNotSupported(ex.Message, expression); } return(res); } throw new NotSupportedException( string.Format("Unable to translate expression {0} to journal operation", expression)); }
private ResultSetBuilder EvaluateCompare(Expression exp) { var memberName = ExHelper.GetMemberName(exp, _itemType); var literal = ExHelper.GetLiteralValue(exp, _parameters); var columnMetadata = GetTimestamp(_journal.Metadata); if (columnMetadata != null && string.Equals(columnMetadata.PropertyName, memberName, StringComparison.OrdinalIgnoreCase) && (literal is long || literal is DateTime)) { DateInterval filterInterval; var nodeType = exp.NodeType; if (exp.GetLeft().NodeType == ExpressionType.Constant) { nodeType = InvertComarison(nodeType); } switch (nodeType) { case ExpressionType.GreaterThan: var timestamp = literal is long ?DateUtils.UnixTimestampToDateTime((long)literal + 1) : ((DateTime)literal).AddTicks(1); filterInterval = DateInterval.From(timestamp); break; case ExpressionType.GreaterThanOrEqual: timestamp = literal is long ?DateUtils.UnixTimestampToDateTime((long)literal) : (DateTime)literal; filterInterval = DateInterval.From(timestamp); break; case ExpressionType.LessThan: timestamp = literal is long ?DateUtils.UnixTimestampToDateTime((long)literal) : (DateTime)literal; filterInterval = DateInterval.To(timestamp); break; case ExpressionType.LessThanOrEqual: timestamp = literal is long ?DateUtils.UnixTimestampToDateTime((long)literal + 1) : ((DateTime)literal).AddTicks(1); filterInterval = DateInterval.To(timestamp); break; default: throw QueryExceptionExtensions.ExpressionNotSupported(string.Format( "Timestamp column operation {0} is not supported. Supported operations are <, >, <=, >=", nodeType), exp); } var result = new ResultSetBuilder(_journal, _tx); result.TimestampInterval(filterInterval); return(result); } throw QueryExceptionExtensions.ExpressionNotSupported( "Comparison is supported for timestamp column only. Unable to bind '{0} to journal query operation", exp); }