internal static string GenerateUpdateSql(DbUpdateCommandTree tree, out List<DbParameter> parameters)
		{
			StringBuilder commandText = new StringBuilder(CommandTextBuilderInitialCapacity);
			ExpressionTranslator translator = new ExpressionTranslator(commandText, tree, null != tree.Returning);
			bool first = true;

			commandText.Append("UPDATE ");
			tree.Target.Expression.Accept(translator);
			commandText.AppendLine();

			// set c1 = ..., c2 = ..., ...            
			commandText.Append("SET ");

			foreach (DbSetClause setClause in tree.SetClauses)
			{
				if (first)
				{
					first = false;
				}
				else
				{
					commandText.Append(", ");
				}

				setClause.Property.Accept(translator);
				commandText.Append(" = ");
				setClause.Value.Accept(translator);

				translator.RegisterMemberValue(setClause.Property, setClause.Value);
			}

			if (first)
			{
				// If first is still true, it indicates there were no set
				// clauses. Introduce a fake set clause so that:
				// - we acquire the appropriate locks
				// - server-gen columns (e.g. timestamp) get recomputed

				EntitySetBase table = ((DbScanExpression)tree.Target.Expression).Target;
				// hope this column isn't indexed to not waste power
				EdmMember someColumn = table.ElementType.Members.Last(x => !IsStoreGenerated(x));
				commandText.AppendFormat("{0} = {0}", GenerateMemberSql(someColumn));
			}
			commandText.AppendLine();

			// where c1 = ..., c2 = ...
			commandText.Append("WHERE ");
			tree.Predicate.Accept(translator);
			commandText.AppendLine();

			// generate returning sql
			GenerateReturningSql(commandText, tree, translator, tree.Returning);

			parameters = translator.Parameters;
			return commandText.ToString();
		}
Esempio n. 2
0
        internal static string GenerateUpdateSql(DbUpdateCommandTree tree, SqlVersion sqlVersion, out List<SqlParameter> parameters)
        {
            const string dummySetParameter = "@p";

            StringBuilder commandText = new StringBuilder(s_commandTextBuilderInitialCapacity);
            ExpressionTranslator translator = new ExpressionTranslator(commandText, tree, null != tree.Returning, sqlVersion);

            if (tree.SetClauses.Count == 0)
            {
                commandText.AppendLine("declare " + dummySetParameter + " int");
            }

            // update [schemaName].[tableName]
            commandText.Append("update ");
            tree.Target.Expression.Accept(translator);
            commandText.AppendLine();

            // set c1 = ..., c2 = ..., ...
            bool first = true;
            commandText.Append("set ");
            foreach (DbSetClause setClause in tree.SetClauses)
            {
                if (first) { first = false; }
                else { commandText.Append(", "); }
                setClause.Property.Accept(translator);
                commandText.Append(" = ");
                setClause.Value.Accept(translator);
            }

            if (first)
            {
                // If first is still true, it indicates there were no set
                // clauses. Introduce a fake set clause so that:
                // - we acquire the appropriate locks
                // - server-gen columns (e.g. timestamp) get recomputed
                //
                // We use the following pattern:
                //
                //  update Foo
                //  set @p = 0
                //  where ...
                commandText.Append(dummySetParameter + " = 0");
            }
            commandText.AppendLine();

            // where c1 = ..., c2 = ...
            commandText.Append("where ");
            tree.Predicate.Accept(translator);
            commandText.AppendLine();

            // generate returning sql
            GenerateReturningSql(commandText, tree, null, translator, tree.Returning, false); 

            parameters = translator.Parameters;
            return commandText.ToString();
        }
Esempio n. 3
0
        internal static string GenerateUpdateSql(DbUpdateCommandTree tree, out List<DbParameter> parameters)
        {
            StringBuilder commandText = new StringBuilder(s_commandTextBuilderInitialCapacity);
            ExpressionTranslator translator = new ExpressionTranslator(commandText, tree, null != tree.Returning);

            // update [schemaName].[tableName]
            commandText.Append("update ");
            tree.Target.Expression.Accept(translator);
            commandText.AppendLine();

            // set c1 = ..., c2 = ..., ...
            bool first = true;
            commandText.Append("set ");
            foreach (DbSetClause setClause in tree.SetClauses)
            {
                if (first) { first = false; }
                else { commandText.Append(", "); }
                setClause.Property.Accept(translator);
                commandText.Append(" = ");
                setClause.Value.Accept(translator);
            }

            if (first)
            {
                // If first is still true, it indicates there were no set
                // clauses. Introduce a fake set clause so that:
                // - we acquire the appropriate locks
                // - server-gen columns (e.g. timestamp) get recomputed
                //
                // We use the following pattern:
                //
                //  update SomeTable
                //  set @i = 0
                //  where ...
                DbParameter parameter = 
                    translator.CreateParameter(
                    default(Int32), 
                    TypeUsage.CreateDefaultTypeUsage(PrimitiveType.GetEdmPrimitiveType(PrimitiveTypeKind.Int32)));

                commandText.Append(parameter.ParameterName);
                commandText.Append(" = 0");
            }
            commandText.AppendLine();

            // where c1 = ..., c2 = ...
            commandText.Append("where ");
            tree.Predicate.Accept(translator);
            commandText.AppendLine();

            // generate returning sql
            GenerateReturningSql(commandText, tree, translator, tree.Returning); 

            parameters = translator.Parameters;
            return commandText.ToString();
        }
 protected virtual void VisitUpdateCommandTree(DbUpdateCommandTree updateTree)
 {
     EntityUtil.CheckArgumentNull(updateTree, "updateTree");
     this.VisitExpressionBindingPre(updateTree.Target);
     this.VisitModificationClauses(updateTree.SetClauses);
     this.VisitExpression(updateTree.Predicate);
     if (updateTree.Returning != null)
     {
         this.VisitExpression(updateTree.Returning);
     }
     this.VisitExpressionBindingPost(updateTree.Target);
 }
        /// <summary>
        /// This method is added as a part of the fix for bug 13533
        /// In this method we try to see from the command tree whether there is any 
        /// updatable column(Property) available on the table(EntityType)
        private static bool GetUpdatableColumn(DbUpdateCommandTree tree, out string updatableColumnName)
        {
            var result = false;
            updatableColumnName = "";
            var entityType = (EntityType)tree.Target.VariableType.EdmType;

            foreach (var edmProperty in entityType.Properties)
            {
                if (entityType.KeyMembers.Contains(edmProperty.Name))
                {
                    // continue if it is a primary key
                    continue;
                }
                if (rowversionString == edmProperty.TypeUsage.EdmType.Name)
                {
                    // if the property is of type rowversion then we continue checking the next item in the list
                    continue;
                }

                // check whether the property is a identity type
                if (edmProperty.TypeUsage.Facets.Contains(storeGeneratedPatternString))
                {
                    var fct = edmProperty.TypeUsage.Facets.GetValue(storeGeneratedPatternString, false);
                    if (StoreGeneratedPattern.Identity
                        == (StoreGeneratedPattern)fct.Value)
                    {
                        // continue to check for the next property if the current property is a identity
                        continue;
                    }
                }
                //if the column is found then return the column name string
                updatableColumnName = edmProperty.Name;
                result = true;
                break;
            }

            return result;
        }
        internal static string[] GenerateUpdateSql(DbUpdateCommandTree tree, out List<DbParameter> parameters, bool isLocalProvider)
        {
            var commandTexts = new List<String>();
            var commandText = new StringBuilder(s_commandTextBuilderInitialCapacity);
            var translator = new ExpressionTranslator(commandText, tree, null != tree.Returning, isLocalProvider);

            // update [schemaName].[tableName]
            commandText.Append("update ");
            tree.Target.Expression.Accept(translator);
            commandText.AppendLine();

            // set c1 = ..., c2 = ..., ...
            var first = true;
            commandText.Append("set ");
            foreach (DbSetClause setClause in tree.SetClauses)
            {
                if (first)
                {
                    first = false;
                }
                else
                {
                    commandText.Append(", ");
                }
                setClause.Property.Accept(translator);
                commandText.Append(" = ");
                setClause.Value.Accept(translator);
            }

            if (first)
            {
                // If first is still true, it indicates there were no set
                // clauses. 
                // - we acquire the appropriate locks
                // - server-gen columns (e.g. timestamp) get recomputed
                //

                // Bug fix #13533 : A fake update DML updating some column item 
                // with the same value as before to acquire the lock on the table 
                // while updating some columns in another table. This happens when
                // both the table are dependent on an entity and the members of entity
                // which is mapped to one table is being updated and the other table 
                // needs to be locked for consistancy.
                string updatableColumnName;
                if (GetUpdatableColumn(tree, out updatableColumnName))
                {
                    commandText.Append("[");
                    commandText.Append(CommonUtils.EscapeSquareBraceNames(updatableColumnName));
                    commandText.Append("] ");
                    commandText.Append(" = ");
                    commandText.Append("[");
                    commandText.Append(CommonUtils.EscapeSquareBraceNames(updatableColumnName));
                    commandText.Append("] ");
                }
                else
                {
                    // Throw some meaningful error
                    throw ADP1.Update(
                        EntityRes.GetString(EntityRes.UpdateStatementCannotBeGeneratedForAcquiringLock),
                        null);
                }
            }
            commandText.AppendLine();

            // where c1 = ..., c2 = ...
            commandText.Append("where ");
            tree.Predicate.Accept(translator);
            commandText.AppendLine();

            commandTexts.Add(commandText.ToString());
            commandText.Length = 0;

            // generate returning sql
            GenerateReturningSql(commandText, tree, translator, tree.Returning);

            if (!String.IsNullOrEmpty(commandText.ToString()))
            {
                commandTexts.Add(commandText.ToString());
            }

            parameters = translator.Parameters;

            return commandTexts.ToArray();
        }
 public SqlUpdateGenerator(DbUpdateCommandTree commandTree)
 {
     _commandTree = commandTree;
 }
 protected virtual void VisitUpdateCommandTree(DbUpdateCommandTree updateTree)
 {
     EntityUtil.CheckArgumentNull(updateTree, "updateTree");
     this.VisitExpressionBindingPre(updateTree.Target);
     this.VisitModificationClauses(updateTree.SetClauses);
     this.VisitExpression(updateTree.Predicate);
     if (updateTree.Returning != null)
     {
         this.VisitExpression(updateTree.Returning);
     }
     this.VisitExpressionBindingPost(updateTree.Target);
 }
        private DbModificationCommandTree RebuildCommandTree(DbModificationCommandTree originalTree, Dictionary<DbSetClause, DbSetClause> clauseMappings)
        {
            if (clauseMappings.Count == 0)
            {
                return originalTree;
            }

            DbModificationCommandTree result;
            Debug.Assert(originalTree.CommandTreeKind == DbCommandTreeKind.Insert || originalTree.CommandTreeKind == DbCommandTreeKind.Update, "Set clauses specified for a modification tree that is not an update or insert tree?");
            if (originalTree.CommandTreeKind == DbCommandTreeKind.Insert)
            {
                DbInsertCommandTree insertTree = (DbInsertCommandTree)originalTree;
                result = new DbInsertCommandTree(insertTree.MetadataWorkspace, insertTree.DataSpace, 
                    insertTree.Target, ReplaceClauses(insertTree.SetClauses, clauseMappings).AsReadOnly(), insertTree.Returning);
            }
            else
            {
                DbUpdateCommandTree updateTree = (DbUpdateCommandTree)originalTree;
                result = new DbUpdateCommandTree(updateTree.MetadataWorkspace, updateTree.DataSpace,
                    updateTree.Target, updateTree.Predicate, ReplaceClauses(updateTree.SetClauses, clauseMappings).AsReadOnly(), updateTree.Returning);
            }

            return result;
        }
        /// <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;
        }
 protected virtual void VisitUpdateCommandTree(DbUpdateCommandTree updateTree)
 {
     //Contract.Requires(updateTree != null);
     VisitExpressionBindingPre(updateTree.Target);
     VisitModificationClauses(updateTree.SetClauses);
     VisitExpression(updateTree.Predicate);
     if (updateTree.Returning != null)
     {
         VisitExpression(updateTree.Returning);
     }
     VisitExpressionBindingPost(updateTree.Target);
 }