internal static TypeUsage ValidateFilter( DbExpressionBinding input, DbExpression predicate) { ArgumentValidation.RequireCompatibleType(predicate, PrimitiveTypeKind.Boolean, nameof(predicate)); return(input.Expression.ResultType); }
public static DbExpression Convert(DynamicFilterDefinition filter, DbExpressionBinding binding, DbContext dbContext, DataSpace dataSpace) { var visitor = new LambdaToDbExpressionVisitor(filter, binding, dbContext, dataSpace); var expression = visitor.Visit(filter.Predicate) as LambdaExpression; var dbExpression = visitor.GetDbExpressionForExpression(expression.Body); if (dbExpression is DbPropertyExpression) { // Special case to handle a condition that is just a plain "boolFlag" or a nullable generic condition. // For a nullable type, we only get here when the filter has either not specified a value for the nullable // parameter or it has specified "null" - both evaluate the same as far as the method prototypes can tell // since the method signature is "param = null". This needs to generate a sql "is null" condition. // Otherwise, no param value was specified so we are assuming that we need to generate a "positive" // condition. i.e. the filter just said "b.prop" which generally means "b.prop == true". // To generate that condition correctly for all types (may not necessarily be a bool), we create a condition // like "!(b.prop == [defaultValue])" if (IsNullableType(expression.Body.Type)) { dbExpression = DbExpressionBuilder.IsNull(dbExpression); } else { var defaultValue = DbExpressionBuilder.Constant(dbExpression.ResultType, Activator.CreateInstance(expression.Body.Type)); dbExpression = DbExpressionBuilder.Not(DbExpressionBuilder.Equal(dbExpression, defaultValue)); } } return(dbExpression); }
/// <summary> /// This method is called by <see cref="Visit(DbFilterExpression)"/> and /// <see cref="Visit(DbQuantifierExpression)"/> /// /// </summary> /// <param name="input"></param> /// <param name="predicate"></param> /// <param name="negatePredicate">This is passed from <see cref="Visit(DbQuantifierExpression)"/> /// in the All(...) case.</param> /// <returns></returns> private SqlSelectStatement VisitFilterExpression(DbExpressionBinding input, DbExpression predicate, bool negatePredicate) { Symbol fromSymbol; var result = VisitInputExpression(input.Expression, input.VariableName, input.VariableType, out fromSymbol); // Filter is compatible with OrderBy // but not with Project, another Filter or GroupBy if (!IsCompatible(result, DbExpressionKind.Filter)) { result = CreateNewSelectStatement(result, input.VariableName, input.VariableType, out fromSymbol); } selectStatementStack.Push(result); symbolTable.EnterScope(); AddFromSymbol(result, input.VariableName, fromSymbol); if (negatePredicate) { result.Where.Append("NOT ("); } result.Where.Append(predicate.Accept(this)); if (negatePredicate) { result.Where.Append(")"); } symbolTable.ExitScope(); selectStatementStack.Pop(); return(result); }
/// <summary> /// Builds insert command. /// </summary> /// <param name="newRow">Row to insert.</param> /// <param name="processor">Context for the table we're inserting into.</param> /// <returns>Insert command.</returns> internal UpdateCommand BuildInsertCommand(PropagatorResult newRow, TableChangeProcessor processor) { // Bind the insert target DbExpressionBinding target = GetTarget(processor); // Create set clauses and returning parameter Dictionary <int, string> outputIdentifiers; DbExpression returning; bool rowMustBeTouched = true; // for inserts, the row must always be touched List <DbModificationClause> setClauses = new List <DbModificationClause>(); foreach (DbModificationClause clause in BuildSetClauses(target, newRow, null, processor, /* insertMode */ true, out outputIdentifiers, out returning, ref rowMustBeTouched)) { setClauses.Add(clause); } // Initialize DML command tree DbInsertCommandTree commandTree = new DbInsertCommandTree(m_translator.MetadataWorkspace, DataSpace.SSpace, target, setClauses.AsReadOnly(), returning); // Create command UpdateCommand command = new DynamicUpdateCommand(processor, m_translator, ModificationOperator.Insert, null, newRow, commandTree, outputIdentifiers); return(command); }
private DbExpression BuildPredicate( DbExpressionBinding target, PropagatorResult referenceRow, PropagatorResult current, TableChangeProcessor processor, ref bool rowMustBeTouched) { Dictionary <EdmProperty, PropagatorResult> dictionary = new Dictionary <EdmProperty, PropagatorResult>(); int ordinal = 0; foreach (EdmProperty property in processor.Table.ElementType.Properties) { PropagatorResult memberValue = referenceRow.GetMemberValue(ordinal); PropagatorResult input = current == null ? (PropagatorResult)null : current.GetMemberValue(ordinal); if (!rowMustBeTouched && (UpdateCompiler.HasFlag(memberValue, PropagatorFlags.ConcurrencyValue) || UpdateCompiler.HasFlag(input, PropagatorFlags.ConcurrencyValue))) { rowMustBeTouched = true; } if (!dictionary.ContainsKey(property) && (UpdateCompiler.HasFlag(memberValue, PropagatorFlags.ConcurrencyValue | PropagatorFlags.Key) || UpdateCompiler.HasFlag(input, PropagatorFlags.ConcurrencyValue | PropagatorFlags.Key))) { dictionary.Add(property, memberValue); } ++ordinal; } DbExpression left = (DbExpression)null; foreach (KeyValuePair <EdmProperty, PropagatorResult> keyValuePair in dictionary) { DbExpression equalityExpression = this.GenerateEqualityExpression(target, keyValuePair.Key, keyValuePair.Value); left = left != null ? (DbExpression)left.And(equalityExpression) : equalityExpression; } return(left); }
private SqlFragment HandleJoinExpression(DbExpressionBinding left, DbExpressionBinding right, DbExpressionKind joinType, DbExpression joinCondition) { JoinFragment join = new JoinFragment(); join.JoinType = Metadata.GetOperator(joinType); join.Left = VisitInputExpression(left.Expression, left.VariableName, left.VariableType); join.Left = WrapJoinInputIfNecessary(join.Left, false); join.Right = VisitInputExpression(right.Expression, right.VariableName, right.VariableType); join.Right = WrapJoinInputIfNecessary(join.Right, true); if (join.Right is SelectStatement) { SelectStatement select = join.Right as SelectStatement; if (select.IsWrapped) { select.Name = right.VariableName; } } // now handle the ON case if (joinCondition != null) { join.Condition = joinCondition.Accept(this); } return(join); }
public static DbExpression Convert(DynamicFilterDefinition filter, DbExpressionBinding binding, ObjectContext objectContext) { var visitor = new LambdaToDbExpressionVisitor(filter, binding, objectContext); var expression = visitor.Visit(filter.Predicate) as LambdaExpression; return(visitor.GetDbExpressionForExpression(expression.Body)); }
// Effects: given a property, produces a property expression // Requires: all arguments are set private static DbExpression GeneratePropertyExpression(DbExpressionBinding target, EdmProperty property) { DebugCheck.NotNull(target); DebugCheck.NotNull(property); return(target.Variable.Property(property)); }
internal static ReadOnlyCollection <DbExpressionBinding> ValidateCrossJoin( IEnumerable <DbExpressionBinding> inputs, out TypeUsage resultType) { List <DbExpressionBinding> expressionBindingList = new List <DbExpressionBinding>(); List <KeyValuePair <string, TypeUsage> > columns = new List <KeyValuePair <string, TypeUsage> >(); Dictionary <string, int> dictionary = new Dictionary <string, int>(); IEnumerator <DbExpressionBinding> enumerator = inputs.GetEnumerator(); int index = 0; while (enumerator.MoveNext()) { DbExpressionBinding current = enumerator.Current; string paramName = StringUtil.FormatIndex(nameof(inputs), index); if (current == null) { throw new ArgumentNullException(paramName); } int num = -1; if (dictionary.TryGetValue(current.VariableName, out num)) { throw new ArgumentException(Strings.Cqt_CrossJoin_DuplicateVariableNames((object)num, (object)index, (object)current.VariableName)); } expressionBindingList.Add(current); dictionary.Add(current.VariableName, index); columns.Add(new KeyValuePair <string, TypeUsage>(current.VariableName, current.VariableType)); ++index; } if (expressionBindingList.Count < 2) { throw new ArgumentException(Strings.Cqt_CrossJoin_AtLeastTwoInputs, nameof(inputs)); } resultType = ArgumentValidation.CreateCollectionOfRowResultType(columns); return(new ReadOnlyCollection <DbExpressionBinding>((IList <DbExpressionBinding>)expressionBindingList)); }
internal ProjectionCollapser( Dictionary <string, DbExpression> varRefMemberBindings, DbExpressionBinding outerBinding) { m_varRefMemberBindings = varRefMemberBindings; m_outerBinding = outerBinding; }
/// <summary> /// Dumps a DbExpressionBinding including its VariableName and DbExpression /// </summary> /// <param name="binding"> The DbExpressionBinding to dump </param> internal void Dump(DbExpressionBinding binding) { Begin("DbExpressionBinding", "VariableName", binding.VariableName); Begin("Expression"); Dump(binding.Expression); End("Expression"); End("DbExpressionBinding"); }
internal void Dump(DbExpressionBinding binding) { this.Begin("DbExpressionBinding", "VariableName", (object)binding.VariableName); this.Begin("Expression"); this.Dump(binding.Expression); this.End("Expression"); this.End("DbExpressionBinding"); }
private DbExpressionEntitySetInfo VisitExpressionBinding(DbExpressionBinding binding) { if (binding != null) { return(VisitExpression(binding.Expression)); } return(null); }
private void VisitBinding(DbExpressionBinding binding) { _key.Append("BV"); VisitVariableName(binding.VariableName); _key.Append("=("); binding.Expression.Accept(this); _key.Append(')'); }
private LambdaToDbExpressionVisitor(DynamicFilterDefinition filter, DbExpressionBinding binding, DbContext dbContext, DataSpace dataSpace) { _Filter = filter; _Binding = binding; _DbContext = dbContext; _ObjectContext = ((IObjectContextAdapter)dbContext).ObjectContext; _DataSpace = dataSpace; }
private void VisitBinding(DbExpressionBinding binding) { this._key.Append("BV"); this.VisitVariableName(binding.VariableName); this._key.Append("=("); binding.Expression.Accept((DbExpressionVisitor)this); this._key.Append(')'); }
internal DbExpression ParseLambda(DbExpressionBinding input, LambdaExpression lamda) { bindContext.Push(lamda.Parameters[0], input.Parameter); var dbExpression = Parse(lamda.Body); bindContext.Pop(); return(dbExpression); }
protected virtual void VisitExpressionBindingPre(DbExpressionBinding binding) { if (binding == null) { throw new ArgumentException("binding"); } VisitExpression(binding.Expression); }
private ViewValidator.DbExpressionEntitySetInfo VisitExpressionBinding( DbExpressionBinding binding) { if (binding != null) { return(this.VisitExpression(binding.Expression)); } return((ViewValidator.DbExpressionEntitySetInfo)null); }
/// <summary> /// Determines predicate used to identify a row in a table. /// </summary> /// <remarks> /// Columns are included in the list when: /// <list> /// <item>They are keys for the table</item> /// <item>They are concurrency values</item> /// </list> /// </remarks> /// <param name="target"> Expression binding representing the table containing the row </param> /// <param name="referenceRow"> Values for the row being located. </param> /// <param name="current"> Values being updated (may be null). </param> /// <param name="processor"> Context for the table containing the row. </param> /// <param name="rowMustBeTouched"> Output parameter indicating whether a row must be touched (whether it's being modified or not) because it contains a concurrency value </param> /// <returns> Column/value pairs. </returns> private DbExpression BuildPredicate( DbExpressionBinding target, PropagatorResult referenceRow, PropagatorResult current, TableChangeProcessor processor, ref bool rowMustBeTouched) { var whereClauses = new Dictionary <EdmProperty, PropagatorResult>(); // add all concurrency tokens (note that keys are always concurrency tokens as well) var propertyOrdinal = 0; foreach (var member in processor.Table.ElementType.Properties) { // members and result values are ordinally aligned var expectedValue = referenceRow.GetMemberValue(propertyOrdinal); var newValue = null == current ? null : current.GetMemberValue(propertyOrdinal); // check if the rowMustBeTouched value should be set to true (if it isn't already // true and we've come across a concurrency value) if (!rowMustBeTouched && (HasFlag(expectedValue, PropagatorFlags.ConcurrencyValue) || HasFlag(newValue, PropagatorFlags.ConcurrencyValue))) { rowMustBeTouched = true; } // determine if this is a concurrency value if (!whereClauses.ContainsKey(member) && // don't add to the set clause twice (HasFlag(expectedValue, PropagatorFlags.ConcurrencyValue | PropagatorFlags.Key) || HasFlag(newValue, PropagatorFlags.ConcurrencyValue | PropagatorFlags.Key))) // tagged as concurrency value { whereClauses.Add(member, expectedValue); } propertyOrdinal++; } // Build a binary AND expression tree from the clauses DbExpression predicate = null; foreach (var clause in whereClauses) { var clauseExpression = GenerateEqualityExpression(target, clause.Key, clause.Value); if (null == predicate) { predicate = clauseExpression; } else { predicate = predicate.And(clauseExpression); } } Debug.Assert(null != predicate, "some predicate term must exist"); return(predicate); }
private DbExpression RewriteCollection(DbExpression expression) { DbExpression dbExpression = expression; DbProjectExpression projectExpression = (DbProjectExpression)null; if (DbExpressionKind.Project == expression.ExpressionKind) { projectExpression = (DbProjectExpression)expression; dbExpression = projectExpression.Input.Expression; } ObjectSpanRewriter.NavigationInfo navInfo = (ObjectSpanRewriter.NavigationInfo)null; if (this.RelationshipSpan) { dbExpression = ObjectSpanRewriter.RelationshipNavigationVisitor.FindNavigationExpression(dbExpression, this._aliasGenerator, out navInfo); } if (navInfo != null) { this.EnterNavigationCollection(navInfo); } else { this.EnterCollection(); } DbExpression body = expression; if (projectExpression != null) { DbExpression projection = this.Rewrite(projectExpression.Projection); if (!object.ReferenceEquals((object)projectExpression.Projection, (object)projection)) { body = (DbExpression)dbExpression.BindAs(projectExpression.Input.VariableName).Project(projection); } } else { DbExpressionBinding input = dbExpression.BindAs(this._aliasGenerator.Next()); DbExpression variable = (DbExpression)input.Variable; DbExpression projection = this.Rewrite(variable); if (!object.ReferenceEquals((object)variable, (object)projection)) { body = (DbExpression)input.Project(projection); } } this.ExitCollection(); if (navInfo != null && navInfo.InUse) { body = (DbExpression)DbExpressionBuilder.Lambda(body, (IEnumerable <DbVariableReferenceExpression>) new List <DbVariableReferenceExpression>(1) { navInfo.SourceVariable }).Invoke((IEnumerable <DbExpression>) new List <DbExpression>(1) { navInfo.Source }); } return(body); }
private void Write(string name, DbExpressionBinding binding) { // WriteLine(binding.GetType().Name); WriteLine(string.Format("{0} ({1}): {2}", name, binding.GetType().Name, binding.VariableType)); _depth++; Write("VariableName", binding.VariableName); Write("Expression", binding.Expression); Write("Variable", binding.Variable); _depth--; }
private DbExpressionEntitySetInfo VisitExpressionBinding(DbExpressionBinding binding) { DbExpressionBinding result = binding; if (binding != null) { return(this.VisitExpression(binding.Expression)); } return(null); }
/// <summary> /// Builds an update command. /// </summary> /// <param name="oldRow">Old value of the row being updated.</param> /// <param name="newRow">New value for the row being updated.</param> /// <param name="processor">Context for the table containing row.</param> /// <returns>Update command.</returns> internal UpdateCommand BuildUpdateCommand(PropagatorResult oldRow, PropagatorResult newRow, TableChangeProcessor processor) { // If we're updating a row, the row may not need to be touched (e.g., no concurrency validation required) bool rowMustBeTouched = false; DbExpressionBinding target = GetTarget(processor); // Create set clauses and returning parameter Dictionary <int, string> outputIdentifiers; DbExpression returning; List <DbModificationClause> setClauses = new List <DbModificationClause>(); foreach (DbModificationClause clause in BuildSetClauses( target, newRow, oldRow, processor, /* insertMode */ false, out outputIdentifiers, out returning, ref rowMustBeTouched)) { setClauses.Add(clause); } // Construct predicate identifying the row to modify DbExpression predicate = BuildPredicate(target, oldRow, newRow, processor, ref rowMustBeTouched); if (0 == setClauses.Count) { if (rowMustBeTouched) { List <IEntityStateEntry> stateEntries = new List <IEntityStateEntry>(); stateEntries.AddRange(SourceInterpreter.GetAllStateEntries( oldRow, m_translator, processor.Table)); stateEntries.AddRange(SourceInterpreter.GetAllStateEntries( newRow, m_translator, processor.Table)); if (stateEntries.All(it => (it.State == EntityState.Unchanged))) { rowMustBeTouched = false; } } // Determine if there is nothing to do (i.e., no values to set, // no computed columns, and no concurrency validation required) if (!rowMustBeTouched) { return(null); } } // Initialize DML command tree DbUpdateCommandTree commandTree = new DbUpdateCommandTree(m_translator.MetadataWorkspace, DataSpace.SSpace, target, predicate, setClauses.AsReadOnly(), returning); // Create command UpdateCommand command = new DynamicUpdateCommand(processor, m_translator, ModificationOperator.Update, oldRow, newRow, commandTree, outputIdentifiers); return(command); }
internal virtual DbExpression OfType(TypeUsage type) { // s.OfType<T> is normally translated to s.Filter(e => e is T).Project(e => e as T) DbExpressionBinding rootBinding = _root.BindAs(_aliasGenerator.Next()); DbExpression filter = this.Filter(rootBinding.Filter(rootBinding.Variable.IsOf(type))); OrderByLifterBase filterLifter = GetLifter(filter, _aliasGenerator); DbExpressionBinding filterBinding = filter.BindAs(_aliasGenerator.Next()); DbExpression project = filterLifter.Project(filterBinding.Project(filterBinding.Variable.TreatAs(type))); return(project); }
internal UpdateCommand BuildDeleteCommand( PropagatorResult oldRow, TableChangeProcessor processor) { bool rowMustBeTouched = true; DbExpressionBinding target = UpdateCompiler.GetTarget(processor); DbExpression predicate = this.BuildPredicate(target, oldRow, (PropagatorResult)null, processor, ref rowMustBeTouched); DbDeleteCommandTree deleteCommandTree = new DbDeleteCommandTree(this.m_translator.MetadataWorkspace, DataSpace.SSpace, target, predicate); return((UpdateCommand) new DynamicUpdateCommand(processor, this.m_translator, ModificationOperator.Delete, oldRow, (PropagatorResult)null, (DbModificationCommandTree)deleteCommandTree, (Dictionary <int, string>)null)); }
public override SqlFragment Visit(DbApplyExpression expression) { DbExpressionBinding inputBinding = expression.Input; InputFragment input = VisitInputExpression(inputBinding.Expression, inputBinding.VariableName, inputBinding.VariableType); DbExpressionBinding applyBinding = expression.Apply; InputFragment apply = VisitInputExpression(applyBinding.Expression, applyBinding.VariableName, applyBinding.VariableType); SelectStatement select = new SelectStatement(); bool isInputSelect = false; if (!(input is TableFragment)) { input.Wrap(scope); isInputSelect = true; } apply.Wrap(scope); select.From = input; select.Wrap(scope); if (apply is SelectStatement) { SelectStatement applySel = apply as SelectStatement; foreach (ColumnFragment f in applySel.Columns) { SelectStatement newColSelect = new SelectStatement(); newColSelect.From = applySel.From; newColSelect.Where = applySel.Where; if (isInputSelect) { VisitAndReplaceTableName(newColSelect.Where, (input as SelectStatement).From.Name, input.Name); } newColSelect.Limit = applySel.Limit; newColSelect.Columns.Add(f); newColSelect.Wrap(scope); scope.Add(applySel.From.Name, applySel.From); ColumnFragment newCol = new ColumnFragment(apply.Name, f.ColumnName); newCol.Literal = newColSelect; newCol.PushInput(newCol.ColumnName); newCol.PushInput(apply.Name); select.AddColumn(newCol, scope); if (string.IsNullOrEmpty(newCol.ColumnAlias)) { newColSelect.Name = newCol.ColumnName; newCol.ColumnAlias = newCol.ColumnName; } scope.Remove(newColSelect); } scope.Remove(applySel.From); scope.Remove(apply); } return(select); }
// Effects: given a "clause" in the form of a property/value pair, produces an equality expression. If the // value is null, creates an IsNull expression // Requires: all arguments are set private DbExpression GenerateEqualityExpression(DbExpressionBinding target, EdmProperty property, PropagatorResult value) { Debug.Assert(null != target && null != property && null != value); DbExpression propertyExpression = GeneratePropertyExpression(target, property); DbExpression valueExpression = GenerateValueExpression(property, value); if (valueExpression.ExpressionKind == DbExpressionKind.Null) { return(propertyExpression.IsNull()); } return(propertyExpression.Equal(valueExpression)); }
private DbExpression GenerateEqualityExpression( DbExpressionBinding target, EdmProperty property, PropagatorResult value) { DbExpression propertyExpression = UpdateCompiler.GeneratePropertyExpression(target, property); DbExpression valueExpression = this.GenerateValueExpression(property, value); if (valueExpression.ExpressionKind == DbExpressionKind.Null) { return((DbExpression)propertyExpression.IsNull()); } return((DbExpression)propertyExpression.Equal(valueExpression)); }
internal static TypeUsage ValidateApply( DbExpressionBinding input, DbExpressionBinding apply) { if (input.VariableName.Equals(apply.VariableName, StringComparison.Ordinal)) { throw new ArgumentException(Strings.Cqt_Apply_DuplicateVariableNames); } return(ArgumentValidation.CreateCollectionOfRowResultType(new List <KeyValuePair <string, TypeUsage> >() { new KeyValuePair <string, TypeUsage>(input.VariableName, input.VariableType), new KeyValuePair <string, TypeUsage>(apply.VariableName, apply.VariableType) })); }
/// <summary> /// Dumps a DbExpressionBinding with the specified decoration /// </summary> /// <param name="binding"> The DbExpressionBinding to dump </param> /// <param name="name"> The decorating block name </param> internal void Dump(DbExpressionBinding binding, string name) { Begin(name); Dump(binding); End(name); }
protected virtual void VisitExpressionBindingPost(DbExpressionBinding binding) { }
protected virtual void VisitExpressionBindingPre(DbExpressionBinding binding) { if (binding == null) throw new ArgumentException("binding"); VisitExpression(binding.Expression); }
private SqlFragment HandleJoinExpression(DbExpressionBinding left, DbExpressionBinding right, DbExpressionKind joinType, DbExpression joinCondition) { JoinFragment join = new JoinFragment(); join.JoinType = Metadata.GetOperator(joinType); join.Left = VisitInputExpression(left.Expression, left.VariableName, left.VariableType); join.Left = WrapJoinInputIfNecessary(join.Left, false); join.Right = VisitInputExpression(right.Expression, right.VariableName, right.VariableType); join.Right = WrapJoinInputIfNecessary(join.Right, true); if (join.Right is SelectStatement) { SelectStatement select = join.Right as SelectStatement; if (select.IsWrapped) select.Name = right.VariableName; } // now handle the ON case if (joinCondition != null) join.Condition = joinCondition.Accept(this); return join; }
internal ProjectionCollapser( Dictionary<string, DbExpression> varRefMemberBindings, DbExpressionBinding outerBinding) { m_varRefMemberBindings = varRefMemberBindings; m_outerBinding = outerBinding; }