// <summary> // Providers should override this to return information specific to their provider. // This method should never return null. // </summary> // <param name="informationType"> The name of the information to be retrieved. </param> // <returns> An XmlReader at the begining of the information requested. </returns> protected override XmlReader GetDbInformation(string informationType) { if (informationType == ProviderManifest.StoreSchemaDefinition) { return(GetStoreSchemaDescription()); } if (informationType == ProviderManifest.StoreSchemaMapping) { return(GetStoreSchemaMapping()); } // Use default Conceptual Schema Definition if (informationType == ProviderManifest.ConceptualSchemaDefinition) { return(null); } throw ADP1.ProviderIncompatible(EntityRes.GetString(EntityRes.ProviderReturnedNullForGetDbInformation, informationType)); }
public override TypeUsage GetStoreType(TypeUsage edmType) { Check.NotNull(edmType, "edmType"); Debug.Assert(edmType.EdmType.BuiltInTypeKind == BuiltInTypeKind.PrimitiveType); var primitiveType = edmType.EdmType as PrimitiveType; if (primitiveType == null) { throw ADP1.Argument(EntityRes.GetString(EntityRes.ProviderDoesNotSupportType, edmType.EdmType)); } var facets = edmType.Facets; switch (primitiveType.PrimitiveTypeKind) { case PrimitiveTypeKind.Boolean: return(TypeUsage.CreateDefaultTypeUsage(StoreTypeNameToStorePrimitiveType["bit"])); case PrimitiveTypeKind.Byte: return(TypeUsage.CreateDefaultTypeUsage(StoreTypeNameToStorePrimitiveType["tinyint"])); case PrimitiveTypeKind.Int16: return(TypeUsage.CreateDefaultTypeUsage(StoreTypeNameToStorePrimitiveType["smallint"])); case PrimitiveTypeKind.Int32: return(TypeUsage.CreateDefaultTypeUsage(StoreTypeNameToStorePrimitiveType["int"])); case PrimitiveTypeKind.Int64: return(TypeUsage.CreateDefaultTypeUsage(StoreTypeNameToStorePrimitiveType["bigint"])); case PrimitiveTypeKind.Guid: return(TypeUsage.CreateDefaultTypeUsage(StoreTypeNameToStorePrimitiveType["uniqueidentifier"])); case PrimitiveTypeKind.Double: return(TypeUsage.CreateDefaultTypeUsage(StoreTypeNameToStorePrimitiveType["float"])); case PrimitiveTypeKind.Single: return(TypeUsage.CreateDefaultTypeUsage(StoreTypeNameToStorePrimitiveType["real"])); case PrimitiveTypeKind.Decimal: // decimal, numeric, money { byte precision; if (!TypeHelpers.TryGetPrecision(edmType, out precision)) { precision = 18; } byte scale; if (!TypeHelpers.TryGetScale(edmType, out scale)) { scale = 0; } var tu = TypeUsage.CreateDecimalTypeUsage(StoreTypeNameToStorePrimitiveType["decimal"], precision, scale); return(tu); } case PrimitiveTypeKind.Binary: // binary, varbinary, image, timestamp, rowversion { var isFixedLength = null != facets[ProviderManifest.FixedLengthFacetName].Value && (bool)facets[ProviderManifest.FixedLengthFacetName].Value; var f = facets[ProviderManifest.MaxLengthFacetName]; var isMaxLength = Helper.IsUnboundedFacetValue(f) || null == f.Value || (int)f.Value > binaryMaxSize; var maxLength = !isMaxLength ? (int)f.Value : Int32.MinValue; TypeUsage tu; if (isFixedLength) { tu = TypeUsage.CreateBinaryTypeUsage( StoreTypeNameToStorePrimitiveType["binary"], true, (isMaxLength ? binaryMaxSize : maxLength)); } else { if (null == f.Value) { tu = TypeUsage.CreateBinaryTypeUsage(StoreTypeNameToStorePrimitiveType["varbinary"], false, binaryMaxSize); } else if (Helper.IsUnboundedFacetValue(f) || edmType.EdmType.Name == "image") { tu = TypeUsage.CreateBinaryTypeUsage(StoreTypeNameToStorePrimitiveType["image"], false); } else if ((int)f.Value > binaryMaxSize) { throw ADP1.ColumnGreaterThanMaxLengthNotSupported(edmType.EdmType.Name, binaryMaxSize); } else { tu = TypeUsage.CreateBinaryTypeUsage(StoreTypeNameToStorePrimitiveType["varbinary"], false, maxLength); } } return(tu); } case PrimitiveTypeKind.String: //char, nchar, varchar, nvarchar, ntext, text, xml { var isFixedLength = null != facets[ProviderManifest.FixedLengthFacetName].Value && (bool)facets[ProviderManifest.FixedLengthFacetName].Value; var f = facets[ProviderManifest.MaxLengthFacetName]; // maxlen is true if facet value is unbounded, the value is bigger than the limited string sizes *or* the facet // value is null. this is needed since functions still have maxlength facet value as null var isMaxLength = Helper.IsUnboundedFacetValue(f) || null == f.Value || (int)f.Value > (nvarcharMaxSize); var maxLength = !isMaxLength ? (int)f.Value : Int32.MinValue; TypeUsage tu; if (isFixedLength) { tu = TypeUsage.CreateStringTypeUsage( StoreTypeNameToStorePrimitiveType["nchar"], true, true, (isMaxLength ? nvarcharMaxSize : maxLength)); } else { if (null == f.Value) { // if it is unknown, fallback to nvarchar[4000] instead of ntext since it has limited store semantics tu = TypeUsage.CreateStringTypeUsage( StoreTypeNameToStorePrimitiveType["nvarchar"], true, false, nvarcharMaxSize); } else if (Helper.IsUnboundedFacetValue(f) || edmType.EdmType.Name == "ntext") { tu = TypeUsage.CreateStringTypeUsage(StoreTypeNameToStorePrimitiveType["ntext"], true, false); } else if ((int)f.Value > nvarcharMaxSize) { throw ADP1.ColumnGreaterThanMaxLengthNotSupported(edmType.EdmType.Name, nvarcharMaxSize); } else { tu = TypeUsage.CreateStringTypeUsage(StoreTypeNameToStorePrimitiveType["nvarchar"], true, false, maxLength); } } return(tu); } case PrimitiveTypeKind.DateTime: return(TypeUsage.CreateDefaultTypeUsage(StoreTypeNameToStorePrimitiveType["datetime"])); default: throw ADP1.NotSupported( EntityRes.GetString( EntityRes.NoStoreTypeForEdmType, TypeHelpers.GetIdentity(edmType), primitiveType.PrimitiveTypeKind)); } }
public override TypeUsage GetEdmType(TypeUsage storeType) { Check.NotNull(storeType, "storeType"); var storeTypeName = storeType.EdmType.Name.ToLowerInvariant(); if (!base.StoreTypeNameToEdmPrimitiveType.ContainsKey(storeTypeName)) { throw ADP1.Argument(EntityRes.GetString(EntityRes.ProviderDoesNotSupportType, storeTypeName)); } var edmPrimitiveType = base.StoreTypeNameToEdmPrimitiveType[storeTypeName]; var maxLength = 0; var isFixedLen = false; var isUnbounded = true; PrimitiveTypeKind newPrimitiveTypeKind; switch (storeTypeName) { // for some types we just go with simple type usage with no facets case "tinyint": case "smallint": case "bigint": case "bit": case "uniqueidentifier": case "int": return(TypeUsage.CreateDefaultTypeUsage(edmPrimitiveType)); case "nvarchar": newPrimitiveTypeKind = PrimitiveTypeKind.String; isUnbounded = !TypeHelpers.TryGetMaxLength(storeType, out maxLength); isFixedLen = false; break; case "nchar": newPrimitiveTypeKind = PrimitiveTypeKind.String; isUnbounded = !TypeHelpers.TryGetMaxLength(storeType, out maxLength); isFixedLen = true; break; case "ntext": newPrimitiveTypeKind = PrimitiveTypeKind.String; isUnbounded = true; isFixedLen = false; break; case "binary": newPrimitiveTypeKind = PrimitiveTypeKind.Binary; isUnbounded = !TypeHelpers.TryGetMaxLength(storeType, out maxLength); isFixedLen = true; break; case "varbinary": newPrimitiveTypeKind = PrimitiveTypeKind.Binary; isUnbounded = !TypeHelpers.TryGetMaxLength(storeType, out maxLength); isFixedLen = false; break; case "image": newPrimitiveTypeKind = PrimitiveTypeKind.Binary; isUnbounded = true; isFixedLen = false; break; case "timestamp": case "rowversion": return(TypeUsage.CreateBinaryTypeUsage(edmPrimitiveType, true, 8)); case "float": case "real": return(TypeUsage.CreateDefaultTypeUsage(edmPrimitiveType)); case "decimal": case "numeric": { byte precision; byte scale; if (TypeHelpers.TryGetPrecision(storeType, out precision) && TypeHelpers.TryGetScale(storeType, out scale)) { return(TypeUsage.CreateDecimalTypeUsage(edmPrimitiveType, precision, scale)); } else { return(TypeUsage.CreateDecimalTypeUsage(edmPrimitiveType)); } } case "money": return(TypeUsage.CreateDecimalTypeUsage(edmPrimitiveType, 19, 4)); case "datetime": return(TypeUsage.CreateDateTimeTypeUsage(edmPrimitiveType, null)); default: throw ADP1.NotSupported(EntityRes.GetString(EntityRes.ProviderDoesNotSupportType, storeTypeName)); } Debug.Assert( newPrimitiveTypeKind == PrimitiveTypeKind.String || newPrimitiveTypeKind == PrimitiveTypeKind.Binary, "at this point only string and binary types should be present"); switch (newPrimitiveTypeKind) { case PrimitiveTypeKind.String: if (!isUnbounded) { return(TypeUsage.CreateStringTypeUsage(edmPrimitiveType, /*isUnicode*/ true, isFixedLen, maxLength)); } else { return(TypeUsage.CreateStringTypeUsage(edmPrimitiveType, /*isUnicode*/ true, isFixedLen)); } case PrimitiveTypeKind.Binary: if (!isUnbounded) { return(TypeUsage.CreateBinaryTypeUsage(edmPrimitiveType, isFixedLen, maxLength)); } else { return(TypeUsage.CreateBinaryTypeUsage(edmPrimitiveType, isFixedLen)); } default: throw ADP1.NotSupported(EntityRes.GetString(EntityRes.ProviderDoesNotSupportType, storeTypeName)); } }
// <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); } } }
private static void AppendType(StringBuilder builder, EdmProperty column) { var type = column.TypeUsage; // check for rowversion-like configurations Facet storeGenFacet; var isTimestamp = false; if (type.EdmType.Name == "binary" && 8 == (int)type.Facets["MaxLength"].Value && column.TypeUsage.Facets.TryGetValue("StoreGeneratedPattern", false, out storeGenFacet) && storeGenFacet.Value != null && StoreGeneratedPattern.Computed == (StoreGeneratedPattern)storeGenFacet.Value) { isTimestamp = true; builder.Append("rowversion"); } else { var typeName = type.EdmType.Name; builder.Append(typeName); switch (type.EdmType.Name) { case "decimal": case "numeric": AppendSqlInvariantFormat(builder, "({0}, {1})", type.Facets["Precision"].Value, type.Facets["Scale"].Value); break; case "binary": case "varbinary": case "nvarchar": case "varchar": case "char": case "nchar": AppendSqlInvariantFormat(builder, "({0})", type.Facets["MaxLength"].Value); break; default: break; } } builder.Append(column.Nullable ? " null" : " not null"); if (!isTimestamp && column.TypeUsage.Facets.TryGetValue("StoreGeneratedPattern", false, out storeGenFacet) && storeGenFacet.Value != null) { var storeGenPattern = (StoreGeneratedPattern)storeGenFacet.Value; if (storeGenPattern == StoreGeneratedPattern.Identity) { if (type.EdmType.Name == "uniqueidentifier") { builder.Append(" default newid()"); } else { builder.Append(" identity"); } } else if (storeGenPattern == StoreGeneratedPattern.Computed) { if (type.EdmType.Name != "timestamp" && type.EdmType.Name != "rowversion") { // if "IsComputed" is applied to store types that are not intrinsically store generated, throw //throw EntityUtil.NotSupported(Strings.SqlProvider_DdlGeneration_StoreGeneratedPatternNotSupported(Enum.GetName(typeof(StoreGeneratedPattern), storeGenPattern))); throw ADP1.ComputedColumnsNotSupportedException(); } } } }
// <summary> // Function for generating create table statements. // </summary> private void AppendCreateTable(EntitySet entitySet) { var objectBuilder = new StringBuilder(); // Ignore the set if it is a defining query. if (entitySet.MetadataProperties["DefiningQuery"].Value != null) { ignoredEntitySets.Add(entitySet); objectBuilder.Append(" -- Ignoring entity set with defining query: "); // Adding a comment. AppendIdentifierEscapeNewLine(objectBuilder, GetTableName(entitySet)); objectBuilder.AppendLine(); ignoredObjects.Add(objectBuilder.ToString()); } else { objectBuilder.Append("CREATE TABLE "); AppendIdentifier(objectBuilder, GetTableName(entitySet)); objectBuilder.Append(" ("); objectBuilder.AppendLine(); // Column information. foreach (var column in entitySet.ElementType.Properties) { objectBuilder.Append(" "); AppendIdentifier(objectBuilder, column.Name); objectBuilder.Append(" "); AppendType(objectBuilder, column); objectBuilder.Append(","); objectBuilder.AppendLine(); } if (entitySet.ElementType.KeyMembers.Count > 0) { // Primary key information. objectBuilder.Append(" PRIMARY KEY ("); var first = true; foreach (var keyMember in entitySet.ElementType.KeyMembers) { // CodePlex issue: http://entityframework.codeplex.com/workitem/437 // Throw an exception if key member is of server generated guid type. // This is because DML operations won't succeed if key column is of server generated with GUID type. if (IsServerGeneratedGuid(keyMember)) { throw ADP1.ServerGeneratedGuidKeyNotSupportedException(keyMember.Name); } if (first) { first = false; } else { objectBuilder.Append(","); } AppendIdentifier(objectBuilder, keyMember.Name); } objectBuilder.Append(")"); objectBuilder.AppendLine(); } objectBuilder.Append(");"); objectBuilder.AppendLine(); objects.Add(objectBuilder.ToString()); } }