public void HandlIdentity_throws_for_unsupported_identity_type() { var typeUsage = ProviderRegistry.SqlCe4_ProviderManifest.GetStoreType( TypeUsage.CreateDefaultTypeUsage(PrimitiveType.GetEdmPrimitiveType(PrimitiveTypeKind.Guid))); var mockMember = new Mock <EdmMember>(); mockMember.Setup(m => m.TypeUsage).Returns(typeUsage); mockMember.Setup(m => m.Name).Returns("Cheese"); var mockTransalator = new Mock <DmlSqlGenerator.ExpressionTranslator>(); mockTransalator.Setup(m => m.MemberValues).Returns(new Dictionary <EdmMember, DbParameter>()); var builder = new SqlStringBuilder(); Assert.Equal( ADP1.Update_NotSupportedIdentityType("Cheese", "SqlServerCe.uniqueidentifier"), Assert.Throws <InvalidOperationException>( () => DmlSqlGenerator.HandleIdentity( builder, mockTransalator.Object, mockMember.Object, false, new Mock <EntitySetBase>().Object)).Message); }
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 // // 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 consistency. 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()); }
internal static string[] GenerateInsertSql(DbInsertCommandTree 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); // insert [schemaName].[tableName] commandText.Append("insert "); tree.Target.Expression.Accept(translator); if (0 < tree.SetClauses.Count) { // (c1, c2, c3, ...) commandText.Append("("); var first = true; foreach (DbSetClause setClause in tree.SetClauses) { if (first) { first = false; } else { commandText.Append(", "); } setClause.Property.Accept(translator); } commandText.AppendLine(")"); // values c1, c2, ... first = true; commandText.Append("values ("); foreach (DbSetClause setClause in tree.SetClauses) { if (first) { first = false; } else { commandText.Append(", "); } setClause.Value.Accept(translator); translator.RegisterMemberValue(setClause.Property, setClause.Value); } commandText.AppendLine(")"); } else { // default values throw ADP1.NotSupported("Default values not supported"); } 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()); }
internal static void PopulateParameterFromTypeUsage(DbParameter parameter, TypeUsage type) { Check.NotNull(parameter, "parameter"); Check.NotNull(type, "type"); // parameter.Direction - take the default. we don't support output // parameters. parameter.Direction = ParameterDirection.Input; // parameter.IsNullable - from the NullableConstraintAttribute value parameter.IsNullable = TypeSemantics.IsNullable(type); // parameter.ParameterName - set by the caller; // parameter.SourceColumn - not applicable until we have a data adapter; // parameter.SourceColumnNullMapping - not applicable until we have a data adapter; // parameter.SourceVersion - not applicable until we have a data adapter; // parameter.Value - left unset; // parameter.DbType - determined by the TypeMapping; // parameter.Precision - from the TypeMapping; // parameter.Scale - from the TypeMapping; // parameter.Size - from the TypeMapping; Debug.Assert(null != type, "no type mapping?"); if (TypeSemantics.IsPrimitiveType(type, PrimitiveTypeKind.Binary)) { PopulateBinaryParameter(parameter, type, DbType.Binary); } else if (TypeSemantics.IsPrimitiveType(type, PrimitiveTypeKind.Boolean)) { parameter.DbType = DbType.Boolean; } else if (TypeSemantics.IsPrimitiveType(type, PrimitiveTypeKind.Byte)) { parameter.DbType = DbType.Byte; } else if (TypeSemantics.IsPrimitiveType(type, PrimitiveTypeKind.DateTime)) { parameter.DbType = DbType.DateTime; } else if (TypeSemantics.IsPrimitiveType(type, PrimitiveTypeKind.Decimal)) { PopulateDecimalParameter(parameter, type, DbType.Decimal); } else if (TypeSemantics.IsPrimitiveType(type, PrimitiveTypeKind.Double)) { parameter.DbType = DbType.Double; } else if (TypeSemantics.IsPrimitiveType(type, PrimitiveTypeKind.Guid)) { parameter.DbType = DbType.Guid; } else if (TypeSemantics.IsPrimitiveType(type, PrimitiveTypeKind.Single)) { parameter.DbType = DbType.Single; } else if (TypeSemantics.IsPrimitiveType(type, PrimitiveTypeKind.Int16)) { parameter.DbType = DbType.Int16; } else if (TypeSemantics.IsPrimitiveType(type, PrimitiveTypeKind.Int32)) { parameter.DbType = DbType.Int32; } else if (TypeSemantics.IsPrimitiveType(type, PrimitiveTypeKind.Int64)) { parameter.DbType = DbType.Int64; } else if (TypeSemantics.IsPrimitiveType(type, PrimitiveTypeKind.String)) { PopulateStringParameter(parameter, type); } else if (TypeSemantics.IsPrimitiveType(type, PrimitiveTypeKind.Time)) { throw ADP1.NotSupported(EntityRes.GetString(EntityRes.ProviderDoesNotSupportType, "Time")); } else if (TypeSemantics.IsPrimitiveType(type, PrimitiveTypeKind.DateTimeOffset)) { throw ADP1.NotSupported(EntityRes.GetString(EntityRes.ProviderDoesNotSupportType, "DateTimeOffset")); } else { ADP1.NotSupported(" UnKnown data type"); } }
// <summary> // Determines SqlDbType for the given primitive type. Extracts facet // information as well. // </summary> private static SqlDbType GetSqlDbType(TypeUsage type, out int?size, out byte?precision, out byte?scale) { // only supported for primitive type var primitiveTypeKind = TypeSemantics.GetPrimitiveTypeKind(type); size = default(int?); precision = default(byte?); scale = default(byte?); // CONSIDER(CMeek):: add logic for Xml here switch (primitiveTypeKind) { case PrimitiveTypeKind.Binary: // for output parameters, ensure there is space... size = GetParameterSize(type); return(GetBinaryDbType(type)); case PrimitiveTypeKind.Boolean: return(SqlDbType.Bit); case PrimitiveTypeKind.Byte: return(SqlDbType.TinyInt); case PrimitiveTypeKind.Time: throw ADP1.NotSupported(EntityRes.GetString(EntityRes.ProviderDoesNotSupportType, "Time")); case PrimitiveTypeKind.DateTimeOffset: throw ADP1.NotSupported(EntityRes.GetString(EntityRes.ProviderDoesNotSupportType, "DateTimeOffset")); case PrimitiveTypeKind.DateTime: return(SqlDbType.DateTime); case PrimitiveTypeKind.Decimal: precision = GetParameterPrecision(type, null); scale = GetScale(type); return(SqlDbType.Decimal); case PrimitiveTypeKind.Double: return(SqlDbType.Float); case PrimitiveTypeKind.Guid: return(SqlDbType.UniqueIdentifier); case PrimitiveTypeKind.Int16: return(SqlDbType.SmallInt); case PrimitiveTypeKind.Int32: return(SqlDbType.Int); case PrimitiveTypeKind.Int64: return(SqlDbType.BigInt); case PrimitiveTypeKind.SByte: return(SqlDbType.SmallInt); case PrimitiveTypeKind.Single: return(SqlDbType.Real); case PrimitiveTypeKind.String: size = GetParameterSize(type); return(GetStringDbType(type)); default: Debug.Fail("unknown PrimitiveTypeKind " + primitiveTypeKind); return(SqlDbType.Variant); } }
private DbCommand CreateCommand(DbProviderManifest providerManifest, DbCommandTree commandTree) { // DEVNOTE/CAUTION: This method could be called either from Remote or Local Provider. // Ensure that the code works well with the both provider types. // The methods called from the below code also need to be capable // of handling both provider types. // // NOTE: Remote Provider is loaded at runtime, if available. // This is done to remove hard dependency on Remote Provider and // it might not be present in all scenarios. All Remote Provider // type checks need to be done using RemoteProviderHelper class. // Check.NotNull(providerManifest, "providerManifest"); Check.NotNull(commandTree, "commandTree"); if (commandTree is DbFunctionCommandTree) { throw ADP1.NotSupported(EntityRes.GetString(EntityRes.StoredProceduresNotSupported)); } var command = _isLocalProvider ? new SqlCeMultiCommand() : (DbCommand)RemoteProviderHelper.CreateRemoteProviderType(RemoteProvider.SqlCeCommand); command.Connection = null; // don't hold on to the connection when we're going to cache this forever; List <DbParameter> parameters; CommandType commandType; var commandTexts = SqlGenerator.GenerateSql(commandTree, out parameters, out commandType, _isLocalProvider); if (_isLocalProvider) { Debug.Assert(command is SqlCeMultiCommand, "SqlCeMultiCommand expected"); // Set the multiple command texts for the command object ((SqlCeMultiCommand)command).CommandTexts = commandTexts; } else { // Set the command text for the RDP case. Debug.Assert(commandTexts.Length == 1, "BatchQueries are not supported in designer scenarios"); command.CommandText = commandTexts[0]; } command.CommandType = commandType; // Now make sure we populate the command's parameters from the CQT's parameters: // foreach (var queryParameter in commandTree.Parameters) { DbParameter parameter; const bool ignoreMaxLengthFacet = false; parameter = CreateSqlCeParameter( queryParameter.Key, queryParameter.Value, DBNull.Value, ignoreMaxLengthFacet, _isLocalProvider); command.Parameters.Add(parameter); } // Now add parameters added as part of SQL gen (note: this feature is only safe for DML SQL gen which // does not support user parameters, where there is no risk of name collision) // if (null != parameters && 0 < parameters.Count) { if (!(commandTree is DbDeleteCommandTree || commandTree is DbInsertCommandTree || commandTree is DbUpdateCommandTree)) { throw ADP1.InternalError(ADP1.InternalErrorCode.SqlGenParametersNotPermitted); } foreach (var parameter in parameters) { command.Parameters.Add(parameter); } } return(command); }
protected override void DbCreateDatabase(DbConnection connection, int?timeOut, StoreItemCollection storeItemCollection) { Check.NotNull(connection, "connection"); Check.NotNull(storeItemCollection, "storeItemCollection"); // Validate that connection is a SqlCeConnection. ValidateConnection(connection); // We don't support create/delete database operations inside a transaction as they can't be rolled back. if (InTransactionScope()) { throw ADP1.CreateDatabaseNotAllowedWithinTransaction(); } if (_isLocalProvider) { var engine = new SqlCeEngine(DbInterception.Dispatch.Connection.GetConnectionString(connection, new DbInterceptionContext())); engine.CreateDatabase(); engine.Dispose(); } else { try { Type rdpType; // If we are working with RDP, then we will need to invoke the APIs through reflection. var engine = RemoteProviderHelper.GetRemoteSqlCeEngine( DbInterception.Dispatch.Connection.GetConnectionString(connection, new DbInterceptionContext()), out rdpType); Debug.Assert(engine != null); // Invoke the required method on SqlCeEngine. var mi = rdpType.GetMethod("CreateDatabase", new[] { typeof(int?) }); Debug.Assert(mi != null); // We will pass 'timeout' to RDP, this will be used as timeout period for connecting and executing on TDSServer. mi.Invoke(engine, new object[] { timeOut }); } catch (Exception e) { throw e.GetBaseException(); } } // Create the command object depending on provider. var command = connection.CreateCommand(); // Create the command texts from StoreItemCollection. var commandTextCollection = SqlDdlBuilder.CreateObjectsScript(storeItemCollection, false); DbTransaction transaction = null; var interceptionContext = new DbInterceptionContext(); try { // Open the connection. DbInterception.Dispatch.Connection.Open(connection, interceptionContext); // Open a transaction and attach to the command. transaction = DbInterception.Dispatch.Connection.BeginTransaction(connection, new BeginTransactionInterceptionContext()); command.Transaction = transaction; // Execute each statement. foreach (var text in commandTextCollection) { command.CommandText = text; DbInterception.Dispatch.Command.NonQuery(command, new DbCommandInterceptionContext()); } // Commit the transaction. DbInterception.Dispatch.Transaction.Commit(transaction, interceptionContext); } catch (Exception e) { if (transaction != null) { // Rollback the transaction. DbInterception.Dispatch.Transaction.Rollback(transaction, interceptionContext); } // Throw IOE with SqlCeException embedded as inner exception. throw new InvalidOperationException(EntityRes.GetString(EntityRes.IncompleteDatabaseCreation), e); } finally { // Close connection and cleanup objects. if (command != null) { command.Dispose(); } if (transaction != null) { DbInterception.Dispatch.Transaction.Dispose(transaction, interceptionContext); } if (connection != null) { DbInterception.Dispatch.Connection.Close(connection, interceptionContext); } } }