// <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);
                }
            }
        }
Example #7
0
        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();
                    }
                }
            }
        }
Example #8
0
        // <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());
            }
        }