예제 #1
0
            /// <summary>
            /// Initializes a new instance of the <see cref="TableDefinitionData" /> class.
            /// </summary>
            /// <param name="type">The type.</param>
            /// <param name="schemaID">The schema identifier.</param>
            /// <param name="name">The name.</param>
            /// <param name="ordinal">The ordinal.</param>
            /// <param name="columnName">Name of the column.</param>
            /// <param name="columnType">Type of the column.</param>
            /// <param name="columnSize">Size of the column.</param>
            /// <param name="isNullable">if set to <see langword="true" /> [is nullable].</param>
            /// <param name="tableTypeID">The ID of the associated <see cref="SqlType"/> if this table defines a <see cref="SqlType"/>.</param>
            public TableDefinitionData(
                SqlObjectType type,
                int schemaID,
                [NotNull] string name,
                int ordinal,
                [NotNull] string columnName,
                [NotNull] SqlType columnType,
                SqlTypeSize columnSize,
                bool isNullable,
                int?tableTypeID)
            {
                if (name == null)
                {
                    throw new ArgumentNullException("name");
                }
                if (columnName == null)
                {
                    throw new ArgumentNullException("columnName");
                }
                if (columnType == null)
                {
                    throw new ArgumentNullException("columnType");
                }

                Type        = type;
                SchemaID    = schemaID;
                Name        = name;
                Column      = new SqlColumn(ordinal, columnName, columnType, columnSize, isNullable);
                TableTypeID = tableTypeID;
            }
예제 #2
0
            /// <summary>
            /// Initializes a new instance of the <see cref="ProgramDefinitionData" /> class.
            /// </summary>
            /// <param name="type">The type.</param>
            /// <param name="schemaID">The schema identifier.</param>
            /// <param name="name">The name.</param>
            /// <param name="ordinal">The ordinal.</param>
            /// <param name="parameterName">Name of the parameter.</param>
            /// <param name="parameterType">Type of the parameter.</param>
            /// <param name="parameterSize">Size of the parameter.</param>
            /// <param name="parameterDirection">The parameter direction.</param>
            /// <param name="isReadonly">if set to <see langword="true" /> [is readonly].</param>
            public ProgramDefinitionData(
                SqlObjectType type,
                int schemaID,
                [NotNull] string name,
                int ordinal,
                [NotNull] string parameterName,
                [NotNull] SqlType parameterType,
                SqlTypeSize parameterSize,
                ParameterDirection parameterDirection,
                bool isReadonly)
            {
                if (name == null)
                {
                    throw new ArgumentNullException("name");
                }
                if (parameterName == null)
                {
                    throw new ArgumentNullException("parameterName");
                }
                if (parameterType == null)
                {
                    throw new ArgumentNullException("parameterType");
                }

                Type      = type;
                SchemaID  = schemaID;
                Name      = name;
                Parameter = new SqlProgramParameter(
                    ordinal,
                    parameterName,
                    parameterType,
                    parameterSize,
                    parameterDirection,
                    isReadonly);
            }
예제 #3
0
 /// <summary>
 ///   Initializes a new instance of the <see cref="SqlTableType"/> class.
 /// </summary>
 /// <param name="baseType">The base type.</param>
 /// <param name="sqlSchema">The schema name.</param>
 /// <param name="name">The table name.</param>
 /// <param name="defaultSize">The default size information.</param>
 /// <param name="isNullable">
 ///   If set to <see langword="true"/> the value can be <see langword="null"/>.
 /// </param>
 /// <param name="isUserDefined">
 ///   If set to <see langword="true"/> the value is a user defined type.
 /// </param>
 /// <param name="isClr">
 ///   If set to <see langword="true"/> the value is a CLR type.
 /// </param>
 // ReSharper disable once NotNullMemberIsNotInitialized
 internal SqlTableType(
     [CanBeNull] SqlType baseType,
     [NotNull] SqlSchema sqlSchema,
     [NotNull] string name,
     SqlTypeSize defaultSize,
     bool isNullable,
     bool isUserDefined,
     bool isClr)
     : base(
         baseType,
         sqlSchema,
         name,
         defaultSize,
         isNullable,
         isUserDefined,
         isClr,
         true)
 {
 }
예제 #4
0
 /// <summary>
 ///   Initializes a new instance of the <see cref="SqlProgramParameter"/> class.
 /// </summary>
 /// <param name="ordinal">
 ///   The zero-based index that is the parameter position.
 /// </param>
 /// <param name="name">
 ///   <para>The <see cref="DatabaseEntity.FullName">parameter name</see>.</para>
 ///   <para>The name should include the obligatory '@'.</para>
 /// </param>
 /// <param name="type">The type information.</param>
 /// <param name="size">The size information.</param>
 /// <param name="direction">The parameter direction.</param>
 /// <param name="isReadOnly">
 ///   If set to <see langword="true"/> the parameter is <see cref="IsReadOnly">read-only.</see>
 /// </param>
 /// <exception cref="ArgumentNullException"><paramref name="name"/> or <paramref name="type"/> is <see langword="null" />.</exception>
 internal SqlProgramParameter(
     int ordinal,
     [NotNull] string name,
     [NotNull] SqlType type,
     SqlTypeSize size,
     ParameterDirection direction,
     bool isReadOnly)
     : base(name)
 {
     if (name == null)
     {
         throw new ArgumentNullException(nameof(name));
     }
     if (type == null)
     {
         throw new ArgumentNullException(nameof(type));
     }
     Ordinal    = ordinal;
     IsReadOnly = isReadOnly;
     Direction  = direction;
     Type       = type.Size.Equals(size) ? type : new SqlType(type, size);
 }
예제 #5
0
        /// <summary>
        ///   Initializes a new instance of the <see cref="SqlColumn"/> class.
        /// </summary>
        /// <param name="ordinal">The zero-based ordinal of the column.</param>
        /// <param name="name">The column name.</param>
        /// <param name="type">The type of the column's data.</param>
        /// <param name="size">The size information.</param>
        /// <param name="isNullable">
        ///   If set to <see langword="true"/> then the column is nullable.
        /// </param>
        internal SqlColumn(
            int ordinal,
            [NotNull] string name,
            [NotNull] SqlType type,
            SqlTypeSize size,
            bool isNullable)
            : base(name)
            // ReSharper restore PossibleNullReferenceException
        {
            if (name == null)
            {
                throw new ArgumentNullException("name");
            }
            if (type == null)
            {
                throw new ArgumentNullException("type");
            }

            Ordinal    = ordinal;
            IsNullable = isNullable;
            Type       = type.Size.Equals(size) ? type : new SqlType(type, size);

            switch (Type.SqlDbType)
            {
            case SqlDbType.Binary:
            case SqlDbType.Char:
            case SqlDbType.VarBinary:
            case SqlDbType.VarChar:
                SqlMetaData = new SqlMetaData(name, Type.SqlDbType, Type.Size.MaximumLength);
                break;

            case SqlDbType.NChar:
            case SqlDbType.NVarChar:
                SqlMetaData = new SqlMetaData(
                    name,
                    Type.SqlDbType,
                    Type.Size.MaximumLength > 0 ? Type.Size.MaximumLength / 2 : Type.Size.MaximumLength);
                break;

            case SqlDbType.Image:
            case SqlDbType.Text:
            case SqlDbType.NText:
                SqlMetaData = new SqlMetaData(name, Type.SqlDbType);
                break;

            case SqlDbType.Decimal:
                SqlMetaData = new SqlMetaData(
                    name,
                    Type.SqlDbType,
                    Type.Size.Precision,
                    Type.Size.Scale);
                break;

            case SqlDbType.Udt:
                switch (Type.Name)
                {
                case "geography":
                    SqlMetaData = new SqlMetaData(
                        name,
                        Type.SqlDbType,
                        typeof(SqlGeography));
                    break;

                case "geometry":
                    SqlMetaData = new SqlMetaData(
                        name,
                        Type.SqlDbType,
                        typeof(SqlGeometry));
                    break;

                case "hierarchyid":
                    SqlMetaData = new SqlMetaData(
                        name,
                        Type.SqlDbType,
                        typeof(SqlHierarchyId));
                    break;

                default:
                    SqlMetaData = new SqlMetaData(name, Type.SqlDbType);
                    break;
                }
                break;

            default:
                SqlMetaData = new SqlMetaData(name, Type.SqlDbType);
                break;
            }
        }
예제 #6
0
        private async Task <DatabaseSchema> Load(bool forceReload, CancellationToken cancellationToken)
        {
            Instant requested = TimeHelpers.Clock.Now;

            using (await _lock.LockAsync(cancellationToken).ConfigureAwait(false))
            {
                // Check to see if the currently loaded schema is acceptable.
                CurrentSchema current = _current;

                // ReSharper disable once ConditionIsAlwaysTrueOrFalse
                if ((current != null) &&
                    (!forceReload || (current.Loaded > requested)))
                {
                    // Rethrow load errors.
                    if (current.ExceptionDispatchInfo != null)
                    {
                        current.ExceptionDispatchInfo.Throw();
                    }

                    Debug.Assert(current.Schema != null);
                    return(this);
                }

                // Create dictionaries
                Dictionary <int, SqlSchema>  sqlSchemas  = new Dictionary <int, SqlSchema>();
                Dictionary <int, SqlType>    typesByID   = new Dictionary <int, SqlType>();
                Dictionary <string, SqlType> typesByName =
                    new Dictionary <string, SqlType>(StringComparer.InvariantCultureIgnoreCase);
                Dictionary <string, SqlProgramDefinition> programDefinitions =
                    new Dictionary <string, SqlProgramDefinition>(StringComparer.InvariantCultureIgnoreCase);
                Dictionary <string, SqlTableDefinition> tables =
                    new Dictionary <string, SqlTableDefinition>(StringComparer.InvariantCultureIgnoreCase);

                try
                {
                    // Open a connection
                    using (SqlConnection sqlConnection = new SqlConnection(ConnectionString))
                    {
                        // ReSharper disable once PossibleNullReferenceException
                        await sqlConnection.OpenAsync(cancellationToken).ConfigureAwait(false);

                        Version version;
                        if (!Version.TryParse(sqlConnection.ServerVersion, out version))
                        {
                            throw new DatabaseSchemaException(
                                      () => Resources.DatabaseSchema_Load_CouldNotParseVersionInformation);
                        }
                        Debug.Assert(version != null);

                        if (version.Major < 9)
                        {
                            throw new DatabaseSchemaException(
                                      () => Resources.DatabaseSchema_Load_VersionNotSupported,
                                      version);
                        }

                        string sql = version.Major == 9 ? SQLResources.RetrieveSchema9 : SQLResources.RetrieveSchema10;

                        // Create the command first, as we will reuse on each connection.
                        using (
                            SqlCommand command = new SqlCommand(sql, sqlConnection)
                        {
                            CommandType = CommandType.Text
                        })
                            // Execute command
                            using (SqlDataReader reader =
                                       // ReSharper disable once PossibleNullReferenceException
                                       await
                                       command.ExecuteReaderAsync(CommandBehavior.SequentialAccess, cancellationToken)
                                       .ConfigureAwait(false))
                            {
                                /*
                                 * Load SQL Schemas
                                 */
                                while (await reader.ReadAsync(cancellationToken).ConfigureAwait(false))
                                {
                                    SqlSchema sqlSchema = new SqlSchema(reader.GetInt32(0), reader.GetString(1));
                                    sqlSchemas.Add(sqlSchema.ID, sqlSchema);
                                }

                                if (sqlSchemas.Count < 1)
                                {
                                    throw new DatabaseSchemaException(
                                              () => Resources.DatabaseSchema_Load_CouldNotRetrieveSchemas);
                                }

                                /*
                                 * Load types
                                 */
                                if (!(await reader.NextResultAsync(cancellationToken).ConfigureAwait(false)))
                                {
                                    throw new DatabaseSchemaException(
                                              () => Resources.DatabaseSchema_Load_RanOutOfResultsRetrievingTypes);
                                }

                                while (await reader.ReadAsync(cancellationToken).ConfigureAwait(false))
                                {
                                    int       schemaId = reader.GetInt32(0);
                                    SqlSchema sqlSchema;
                                    if (!sqlSchemas.TryGetValue(schemaId, out sqlSchema) ||
                                        (sqlSchema == null))
                                    {
                                        throw new DatabaseSchemaException(
                                                  () => Resources.DatabaseSchema_Load_CouldNotFindSchema,
                                                  schemaId);
                                    }
                                    int     id   = reader.GetInt32(1);
                                    string  name = reader.GetString(2).ToLower();
                                    SqlType baseType;
                                    if (reader.IsDBNull(3))
                                    {
                                        baseType = null;
                                    }
                                    else
                                    {
                                        // NB SQL returns types in dependency order
                                        // i.e. base types are always seen first, so this code is much easier.
                                        int baseId = reader.GetInt32(3);
                                        typesByID.TryGetValue(baseId, out baseType);
                                    }

                                    short maxLength     = reader.GetInt16(4);
                                    byte  precision     = reader.GetByte(5);
                                    byte  scale         = reader.GetByte(6);
                                    bool  isNullable    = reader.GetBoolean(7);
                                    bool  isUserDefined = reader.GetBoolean(8);
                                    bool  isCLR         = reader.GetBoolean(9);
                                    bool  isTable       = reader.GetBoolean(10);

                                    // Create type
                                    SqlType type = isTable
                                    ? new SqlTableType(
                                        baseType,
                                        sqlSchema,
                                        name,
                                        new SqlTypeSize(maxLength, precision, scale),
                                        isNullable,
                                        isUserDefined,
                                        isCLR)
                                    : new SqlType(
                                        baseType,
                                        sqlSchema,
                                        name,
                                        new SqlTypeSize(maxLength, precision, scale),
                                        isNullable,
                                        isUserDefined,
                                        isCLR);

                                    // Add to dictionary
                                    typesByName.Add(type.FullName, type);
                                    if (!typesByName.ContainsKey(type.Name))
                                    {
                                        typesByName.Add(type.Name, type);
                                    }
                                    typesByID.Add(id, type);
                                }

                                if (typesByName.Count < 1)
                                {
                                    throw new DatabaseSchemaException(
                                              () => Resources.DatabaseSchema_Load_CouldNotRetrieveTypes);
                                }

                                /*
                                 * Load program definitions
                                 */
                                if (!(await reader.NextResultAsync(cancellationToken).ConfigureAwait(false)))
                                {
                                    throw new DatabaseSchemaException(
                                              () => Resources.DatabaseSchema_Load_RanOutOfResultsRetrievingPrograms);
                                }

                                List <ProgramDefinitionData> programDefinitionData = new List <ProgramDefinitionData>();
                                while (await reader.ReadAsync(cancellationToken).ConfigureAwait(false))
                                {
                                    SqlObjectType type;
                                    string        typeString = reader.GetString(0) ?? string.Empty;
                                    if (!ExtendedEnum <SqlObjectType> .TryParse(typeString, true, out type))
                                    {
                                        throw new DatabaseSchemaException(
                                                  () => Resources.DatabaseSchema_Load_CouldNotFindTypeWhenLoadingPrograms,
                                                  typeString);
                                    }

                                    int       schemaId = reader.GetInt32(1);
                                    SqlSchema sqlSchema;
                                    if (!sqlSchemas.TryGetValue(schemaId, out sqlSchema))
                                    {
                                        throw new DatabaseSchemaException(
                                                  () => Resources.DatabaseSchema_Load_CouldNotFindSchemaWhenLoadingPrograms,
                                                  schemaId);
                                    }
                                    string name = reader.GetString(2).ToLower();

                                    // If we have a null ordinal, we have no parameters.
                                    if (reader.IsDBNull(3))
                                    {
                                        programDefinitionData.Add(new ProgramDefinitionData(type, schemaId, name));
                                        continue;
                                    }

                                    int     ordinal       = reader.GetInt32(3);
                                    string  parameterName = reader.GetString(4).ToLower();
                                    int     typeId        = reader.GetInt32(5);
                                    SqlType parameterType;
                                    if (!typesByID.TryGetValue(typeId, out parameterType) ||
                                        (parameterType == null))
                                    {
                                        throw new DatabaseSchemaException(
                                                  () => Resources.DatabaseSchema_Load_ParameterTypeNotFound,
                                                  parameterName,
                                                  typeId,
                                                  name);
                                    }

                                    short       maxLength     = reader.GetInt16(6);
                                    byte        precision     = reader.GetByte(7);
                                    byte        scale         = reader.GetByte(8);
                                    SqlTypeSize parameterSize = new SqlTypeSize(maxLength, precision, scale);

                                    bool isOutput = reader.GetBoolean(9);
                                    ParameterDirection parameterDirection;
                                    if (!isOutput)
                                    {
                                        parameterDirection = ParameterDirection.Input;
                                    }
                                    else if (parameterName == string.Empty)
                                    {
                                        parameterDirection = ParameterDirection.ReturnValue;
                                    }
                                    else
                                    {
                                        parameterDirection = ParameterDirection.InputOutput;
                                    }

                                    bool parameterIsReadOnly = reader.GetBoolean(10);
                                    programDefinitionData.Add(
                                        new ProgramDefinitionData(
                                            type,
                                            schemaId,
                                            name,
                                            ordinal,
                                            parameterName,
                                            parameterType,
                                            parameterSize,
                                            parameterDirection,
                                            parameterIsReadOnly));
                                }

                                // Create unique program definitions.
                                foreach (SqlProgramDefinition program in programDefinitionData
                                         // ReSharper disable once PossibleNullReferenceException
                                         .GroupBy(d => d.ToString())
                                         .Select(
                                             g =>
                                {
                                    Debug.Assert(g != null);

                                    // Get columns ordered by ordinal.
                                    SqlProgramParameter[] parameters = g
                                                                       // ReSharper disable once PossibleNullReferenceException
                                                                       .Select(d => d.Parameter)
                                                                       .Where(p => p != null)
                                                                       .OrderBy(p => p.Ordinal)
                                                                       .ToArray();

                                    ProgramDefinitionData first = g.First();
                                    Debug.Assert(first != null);
                                    Debug.Assert(first.Name != null);

                                    Debug.Assert(sqlSchemas != null);

                                    SqlSchema sqlSchema;
                                    if (!sqlSchemas.TryGetValue(first.SchemaID, out sqlSchema))
                                    {
                                        throw new DatabaseSchemaException(
                                            () =>
                                            Resources
                                            .DatabaseSchema_Load_CouldNotFindSchemaLoadingTablesAndViews,
                                            first.SchemaID);
                                    }
                                    Debug.Assert(sqlSchema != null);

                                    return(new SqlProgramDefinition(
                                               first.Type,
                                               sqlSchema,
                                               first.Name,
                                               parameters));
                                }))
                                {
                                    Debug.Assert(program != null);
                                    programDefinitions[program.FullName] = program;

                                    if (!programDefinitions.ContainsKey(program.Name))
                                    {
                                        programDefinitions.Add(program.Name, program);
                                    }
                                }

                                /*
                                 * Load tables and views
                                 */
                                if (!(await reader.NextResultAsync(cancellationToken).ConfigureAwait(false)))
                                {
                                    throw new DatabaseSchemaException(
                                              () => Resources.DatabaseSchema_Load_RanOutOfTablesAndViews);
                                }

                                // Read raw data in.
                                List <TableDefinitionData> tableDefinitionData = new List <TableDefinitionData>();
                                while (await reader.ReadAsync(cancellationToken).ConfigureAwait(false))
                                {
                                    SqlObjectType type;
                                    string        typeString = reader.GetString(0) ?? string.Empty;
                                    if (!ExtendedEnum <SqlObjectType> .TryParse(typeString, true, out type))
                                    {
                                        throw new DatabaseSchemaException(
                                                  () => Resources.DatabaseSchema_Load_CouldNotFindObjectType,
                                                  typeString);
                                    }
                                    int     schemaId   = reader.GetInt32(1);
                                    string  name       = reader.GetString(2).ToLower();
                                    int     ordinal    = reader.GetInt32(3);
                                    string  columnName = reader.GetString(4).ToLower();
                                    int     typeId     = reader.GetInt32(5);
                                    SqlType sqlType;
                                    if (!typesByID.TryGetValue(typeId, out sqlType) ||
                                        (sqlType == null))
                                    {
                                        throw new DatabaseSchemaException(
                                                  () => Resources.DatabaseSchema_Load_ColumnTypeNotFound,
                                                  columnName,
                                                  typeId,
                                                  name);
                                    }

                                    short       maxLength   = reader.GetInt16(6);
                                    byte        precision   = reader.GetByte(7);
                                    byte        scale       = reader.GetByte(8);
                                    SqlTypeSize sqlTypeSize = new SqlTypeSize(maxLength, precision, scale);

                                    bool isNullable = reader.GetBoolean(9);

                                    int?tableType = reader.IsDBNull(10) ? null : (int?)reader.GetInt32(10);

                                    tableDefinitionData.Add(
                                        new TableDefinitionData(
                                            type,
                                            schemaId,
                                            name,
                                            ordinal,
                                            columnName,
                                            sqlType,
                                            sqlTypeSize,
                                            isNullable,
                                            tableType));
                                }

                                // Create unique table definitions.
                                foreach (SqlTableDefinition table in tableDefinitionData
                                         // ReSharper disable once PossibleNullReferenceException
                                         .GroupBy(d => d.ToString())
                                         .Select(
                                             g =>
                                {
                                    Debug.Assert(g != null);

                                    // Get columns ordered by ordinal.
                                    SqlColumn[] columns = g
                                                          // ReSharper disable PossibleNullReferenceException
                                                          .Select(d => d.Column)
                                                          .OrderBy(c => c.Ordinal)
                                                          // ReSharper restore PossibleNullReferenceException
                                                          .ToArray();
                                    Debug.Assert(columns.Length > 0);

                                    TableDefinitionData first = g.First();
                                    Debug.Assert(first != null);
                                    Debug.Assert(first.Name != null);
                                    Debug.Assert(sqlSchemas != null);

                                    SqlSchema sqlSchema;
                                    if (!sqlSchemas.TryGetValue(first.SchemaID, out sqlSchema))
                                    {
                                        throw new DatabaseSchemaException(
                                            () =>
                                            Resources
                                            .DatabaseSchema_Load_CouldNotFindSchemaLoadingTablesAndViews,
                                            first.SchemaID);
                                    }
                                    Debug.Assert(sqlSchema != null);

                                    SqlTableType tableType;
                                    if (first.TableTypeID != null)
                                    {
                                        Debug.Assert(typesByID != null);

                                        SqlType tType;
                                        if (!typesByID.TryGetValue(first.TableTypeID.Value, out tType))
                                        {
                                            throw new DatabaseSchemaException(
                                                () => Resources.DatabaseSchema_Load_TableTypeNotFound,
                                                first.TableTypeID.Value,
                                                first.Name);
                                        }
                                        tableType = tType as SqlTableType;
                                        if (tableType == null)
                                        {
                                            throw new DatabaseSchemaException(
                                                () => Resources.DatabaseSchema_Load_TypeNotTableType,
                                                first.TableTypeID.Value,
                                                first.Name);
                                        }
                                    }
                                    else
                                    {
                                        tableType = null;
                                    }

                                    return(new SqlTableDefinition(
                                               first.Type,
                                               sqlSchema,
                                               first.Name,
                                               columns,
                                               tableType));
                                }))
                                {
                                    Debug.Assert(table != null);
                                    tables[table.FullName] = table;

                                    if (!tables.ContainsKey(table.Name))
                                    {
                                        tables.Add(table.Name, table);
                                    }
                                }
                            }
                    }

                    // Update the current schema.
                    _current = new CurrentSchema(Schema.GetOrAdd(sqlSchemas, programDefinitions, tables, typesByName));

                    // Always return this
                    return(this);
                }
                // In the event of an error we don't set the loaded flag - this allows retries.
                catch (DatabaseSchemaException databaseSchemaException)
                {
                    // Capture the exception in the current schema.
                    _current = new CurrentSchema(ExceptionDispatchInfo.Capture(databaseSchemaException));
                    throw;
                }
                catch (Exception exception)
                {
                    // Wrap exception in Database exception.
                    DatabaseSchemaException databaseSchemaException = new DatabaseSchemaException(
                        exception,
                        LoggingLevel.Critical,
                        () => Resources.DatabaseSchema_Load_ErrorOccurred);
                    // Capture the exception in the current schema.
                    _current = new CurrentSchema(ExceptionDispatchInfo.Capture(databaseSchemaException));
                    throw databaseSchemaException;
                }
            }
        }