internal static bool HandleIdentity( StringBuilder commandText, ExpressionTranslator translator, EdmMember member, bool flag, EntitySetBase target) { DebugCheck.NotNull(commandText); DebugCheck.NotNull(translator); DebugCheck.NotNull(member); DebugCheck.NotNull(target); DbParameter parameter; if (translator.MemberValues.TryGetValue(member, out parameter)) { commandText.Append(parameter.ParameterName); } else { if (flag) { throw ADP1.NotSupported(ADP1.Update_NotSupportedServerGenKey(target.Name)); } if (!IsValidIdentityColumnType(member.TypeUsage)) { throw ADP1.InvalidOperation(ADP1.Update_NotSupportedIdentityType(member.Name, member.TypeUsage.ToString())); } commandText.AppendFormat("CAST (@@IDENTITY AS {0})", member.TypeUsage.EdmType.Name); flag = true; } return(flag); }
/// <summary> /// Generates SQL fragment returning server-generated values. /// Requires: translator knows about member values so that we can figure out /// how to construct the key predicate. /// <code>Sample SQL: /// /// select IdentityValue /// from MyTable /// where IdentityValue = @@identity /// /// NOTE: not scope_identity() because we don't support it.</code> /// </summary> /// <param name="commandText"> Builder containing command text </param> /// <param name="tree"> Modification command tree </param> /// <param name="translator"> Translator used to produce DML SQL statement for the tree </param> /// <param name="returning"> Returning expression. If null, the method returns immediately without producing a SELECT statement. </param> private static void GenerateReturningSql( StringBuilder commandText, DbModificationCommandTree tree, ExpressionTranslator translator, DbExpression returning) { if (returning != null) { commandText.Append("select "); returning.Accept(translator); commandText.AppendLine(); commandText.Append("from "); tree.Target.Expression.Accept(translator); commandText.AppendLine(); commandText.Append("where "); var target = ((DbScanExpression)tree.Target.Expression).Target; var flag = false; var isFirst = true; foreach (var member in target.ElementType.KeyMembers) { DbParameter parameter; if (!isFirst) { commandText.Append(" and "); } else { isFirst = false; } commandText.Append(GenerateMemberTSql(member)); commandText.Append(" = "); if (translator.MemberValues.TryGetValue(member, out parameter)) { commandText.Append(parameter.ParameterName); } else { if (flag) { throw ADP1.NotSupported(ADP1.Update_NotSupportedServerGenKey(target.Name)); } if (!IsValidIdentityColumnType(member.TypeUsage)) { throw ADP1.InvalidOperation(ADP1.Update_NotSupportedIdentityType(member.Name, member.TypeUsage.ToString())); } commandText.Append("@@IDENTITY"); flag = true; } } } }
// <summary> // Chooses the appropriate SqlDbType for the given string type. // </summary> private static SqlDbType GetStringDbType(TypeUsage type) { Debug.Assert( type.EdmType.BuiltInTypeKind == BuiltInTypeKind.PrimitiveType && PrimitiveTypeKind.String == ((PrimitiveType)type.EdmType).PrimitiveTypeKind, "only valid for string type"); SqlDbType dbType; if (type.EdmType.Name.ToUpperInvariant() == "XML") { // vamshikb: throw as SQLCE doesn't support XML datatype. throw ADP1.NotSupported(EntityRes.GetString(EntityRes.ProviderDoesNotSupportType, "XML")); } else { // Specific type depends on whether the string is a unicode string and whether it is a fixed length string. // By default, assume widest type (unicode) and most common type (variable length) bool unicode, fixedLength, isMaxLength = false; int maxLength; if (!TypeHelpers.TryGetIsFixedLength(type, out fixedLength)) { fixedLength = false; } if (!TypeHelpers.TryGetIsUnicode(type, out unicode)) { unicode = true; } if (!TypeHelpers.TryGetMaxLength(type, out maxLength)) { isMaxLength = true; } Debug.Assert(unicode, "SQLCE supports unicode strings only."); // vamshikb: SQLCE supports unicode datatypes only. // Include logic related to the unicode datatypes alone. (unicode == true) if (fixedLength) { dbType = SqlDbType.NChar; } else { dbType = isMaxLength ? SqlDbType.NText : SqlDbType.NVarChar; } } return(dbType); }
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); }