/// <summary>
        ///     Called when an <see cref="DbExpression" /> of an otherwise unrecognized type is encountered.
        /// </summary>
        /// <param name="expression"> The expression </param>
        /// <exception cref="ArgumentNullException">
        ///     <paramref name="expression" />
        ///     is null
        /// </exception>
        /// <exception cref="NotSupportedException">
        ///     Always thrown if this method is called, since it indicates that
        ///     <paramref name="expression" />
        ///     is of an unsupported type
        /// </exception>
        public override void Visit(DbExpression expression)
        {
            // #433613: PreSharp warning 56506: Parameter 'expression' to this public method must be validated: A null-dereference can occur here.
            Check.NotNull(expression, "expression");

            throw ADP1.NotSupported(); // EntityRes.GetString(EntityRes.Cqt_General_UnsupportedExpression, expression.GetType().FullName));
        }
        // <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);
        }
        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);
        }