Example #1
0
        private void ExtendResultMetadata(List <DbColumn[]> columnSchemas, List <ResultSet> results)
        {
            if (columnSchemas.Count != results.Count)
            {
                return;
            }

            for (int i = 0; i < results.Count; i++)
            {
                ResultSet  result       = results[i];
                DbColumn[] columnSchema = columnSchemas[i];
                if (result.Columns.Length > columnSchema.Length)
                {
                    throw new InvalidOperationException("Did not receive enough metadata columns.");
                }

                for (int j = 0; j < result.Columns.Length; j++)
                {
                    DbColumnWrapper resultCol = result.Columns[j];
                    DbColumn        schemaCol = columnSchema[j];

                    if (!string.Equals(resultCol.DataTypeName, schemaCol.DataTypeName, StringComparison.OrdinalIgnoreCase) ||
                        (!string.Equals(resultCol.ColumnName, schemaCol.ColumnName) &&
                         !string.IsNullOrEmpty(schemaCol.ColumnName) &&
                         !string.Equals(resultCol, SR.QueryServiceColumnNull)))
                    {
                        throw new InvalidOperationException("Inconsistent column metadata.");
                    }

                    result.Columns[j] = new DbColumnWrapper(schemaCol);
                }
            }
        }
        /// <summary>
        /// Filters out metadata that is not present in the result set, and matches metadata ordering to resultset.
        /// </summary>
        public static EditColumnMetadata[] FilterColumnMetadata(EditColumnMetadata[] metaColumns, DbColumnWrapper[] resultColumns)
        {
            if (metaColumns.Length == 0)
            {
                return(metaColumns);
            }

            bool escapeColName = FromSqlScript.IsIdentifierBracketed(metaColumns[0].EscapedName);
            Dictionary <string, int> columnNameOrdinalMap = new Dictionary <string, int>(capacity: resultColumns.Length);

            for (int i = 0; i < resultColumns.Length; i++)
            {
                DbColumnWrapper column     = resultColumns[i];
                string          columnName = column.ColumnName;
                if (escapeColName && !FromSqlScript.IsIdentifierBracketed(columnName))
                {
                    columnName = ToSqlScript.FormatIdentifier(columnName);
                }
                columnNameOrdinalMap.Add(columnName, column.ColumnOrdinal ?? i);
            }

            HashSet <string> resultColumnNames = columnNameOrdinalMap.Keys.ToHashSet();

            metaColumns = Array.FindAll(metaColumns, column => resultColumnNames.Contains(column.EscapedName));
            foreach (EditColumnMetadata metaCol in metaColumns)
            {
                metaCol.Ordinal = columnNameOrdinalMap[metaCol.EscapedName];
            }
            Array.Sort(metaColumns, (x, y) => (Comparer <int> .Default).Compare(x.Ordinal, y.Ordinal));

            return(metaColumns);
        }
        /// <summary>
        /// Generates the INSERT INTO statement that will apply the row creation
        /// </summary>
        /// <returns>INSERT INTO statement</returns>
        public override string GetScript()
        {
            // Process the cells and columns
            List <string> inColumns = new List <string>();
            List <string> inValues  = new List <string>();

            for (int i = 0; i < AssociatedObjectMetadata.Columns.Length; i++)
            {
                DbColumnWrapper column = AssociatedResultSet.Columns[i];
                CellUpdate      cell   = newCells[i];

                // Continue if we're not inserting a value for this column
                if (!IsCellValueProvided(column, cell, DefaultValues[i]))
                {
                    continue;
                }

                // Column is provided
                inColumns.Add(AssociatedObjectMetadata.Columns[i].EscapedName);
                inValues.Add(ToSqlScript.FormatValue(cell.AsDbCellValue, column));
            }

            // Build the insert statement
            return(inValues.Count > 0
                ? string.Format(InsertScriptValuesStatement,
                                AssociatedObjectMetadata.EscapedMultipartName,
                                string.Join(", ", inColumns),
                                string.Join(", ", inValues))
                : string.Format(InsertScriptDefaultStatement, AssociatedObjectMetadata.EscapedMultipartName));
        }
        /// <summary>
        /// Generates the INSERT INTO statement that will apply the row creation
        /// </summary>
        /// <returns>INSERT INTO statement</returns>
        public override string GetScript()
        {
            // Process all the cells, and generate the values
            List <string> values = new List <string>();

            for (int i = 0; i < AssociatedResultSet.Columns.Length; i++)
            {
                DbColumnWrapper column = AssociatedResultSet.Columns[i];
                CellUpdate      cell   = newCells[i];

                // Skip columns that cannot be updated
                if (!column.IsUpdatable)
                {
                    continue;
                }

                // If we're missing a cell, then we cannot continue
                if (cell == null)
                {
                    throw new InvalidOperationException(SR.EditDataCreateScriptMissingValue);
                }

                // Format the value and add it to the list
                values.Add(SqlScriptFormatter.FormatValue(cell.Value, column));
            }
            string joinedValues = string.Join(", ", values);

            // Get the start clause
            string start = GetTableClause();

            // Put the whole #! together
            return(string.Format(InsertCompleteScript, start, joinedValues));
        }
        public void DataTypeAndPropertiesTest()
        {
            // check that data types array contains items
            var serverDataTypes = DbColumnWrapper.AllServerDataTypes;

            Assert.True(serverDataTypes.Count > 0);

            // check default constructor doesn't throw
            Assert.NotNull(new DbColumnWrapper());

            // check various properties are either null or not null
            var column  = new TestColumn();
            var wrapper = new DbColumnWrapper(column);

            Assert.NotNull(wrapper.DataType);
            Assert.Null(wrapper.AllowDBNull);
            Assert.Null(wrapper.BaseCatalogName);
            Assert.Null(wrapper.BaseColumnName);
            Assert.Null(wrapper.BaseServerName);
            Assert.Null(wrapper.BaseTableName);
            Assert.Null(wrapper.ColumnOrdinal);
            Assert.Null(wrapper.ColumnSize);
            Assert.Null(wrapper.IsAliased);
            Assert.Null(wrapper.IsAutoIncrement);
            Assert.Null(wrapper.IsExpression);
            Assert.Null(wrapper.IsHidden);
            Assert.Null(wrapper.IsIdentity);
            Assert.Null(wrapper.IsKey);
            Assert.Null(wrapper.IsReadOnly);
            Assert.Null(wrapper.IsUnique);
            Assert.Null(wrapper.NumericPrecision);
            Assert.Null(wrapper.NumericScale);
            Assert.Null(wrapper.UdtAssemblyQualifiedName);
            Assert.Null(wrapper.DataTypeName);
        }
        public void DbColumnConstructorTests()
        {
            // check that various constructor parameters initial the wrapper correctly
            var w1 = new DbColumnWrapper(new TestColumn("varchar", int.MaxValue, "Microsoft SQL Server 2005 XML Showplan"));

            Assert.True(w1.IsXml);

            var w2 = new DbColumnWrapper(new TestColumn("binary"));

            Assert.True(w2.IsBytes);

            var w3 = new DbColumnWrapper(new TestColumn("varbinary", int.MaxValue));

            Assert.True(w3.IsBytes);

            var w4 = new DbColumnWrapper(new TestColumn("sql_variant"));

            Assert.True(w4.IsSqlVariant);

            var w5 = new DbColumnWrapper(new TestColumn("my_udt"));

            Assert.True(w5.IsUdt);

            var w6 = new DbColumnWrapper(new TestColumn("my_hieracrchy", null, null, "MICROSOFT.SQLSERVER.TYPES.SQLHIERARCHYID"));

            Assert.True(w6.IsUdt);
        }
Example #7
0
        public void DateTime2Test(int precision)
        {
            // Setup: Create some test values
            // NOTE: We are doing these here instead of InlineData because DateTime values can't be written as constant expressions
            DateTime[] testValues =
            {
                DateTime.Now, DateTime.UtcNow, DateTime.MinValue, DateTime.MaxValue
            };

            // Setup: Create a DATETIME column
            DbColumnWrapper col = new DbColumnWrapper(new TestDbColumn
            {
                DataTypeName = "DaTeTiMe2",
                NumericScale = precision
            });

            foreach (DateTime value in testValues)
            {
                string displayValue = VerifyReadWrite(sizeof(long) + 1, value, (writer, val) => writer.WriteDateTime(val),
                                                      (reader, rowId) => reader.ReadDateTime(0, rowId, col));

                // Make sure the display value has a time string with variable number of milliseconds
                Assert.True(Regex.IsMatch(displayValue, @"^[\d]{4}-[\d]{2}-[\d]{2} [\d]{2}:[\d]{2}:[\d]{2}"));
                if (precision > 0)
                {
                    Assert.True(Regex.IsMatch(displayValue, $@"\.[\d]{{{precision}}}$"));
                }
            }
        }
Example #8
0
        public void TimeSpanTooLargeTest(string value)
        {
            // If: I create a cell update for a timespan column and provide a value that is over 24hrs
            // Then: It should throw an exception
            DbColumnWrapper col = GetWrapper <TimeSpan>("time");

            Assert.Throws <InvalidOperationException>(() => new CellUpdate(col, value));
        }
Example #9
0
        public void EmptyDataTest()
        {
            EditColumnMetadata[] metas = new EditColumnMetadata[0];
            DbColumnWrapper[]    cols  = new DbColumnWrapper[0];

            EditColumnMetadata[] filteredData = EditTableMetadata.FilterColumnMetadata(metas, cols);
            ValidateFilteredData(filteredData, cols);
        }
Example #10
0
        public void ByteArrayInvalidFormatTest()
        {
            // If: I attempt to create a CellUpdate for a binary column
            // Then: It should throw an exception
            DbColumnWrapper col = GetWrapper <byte[]>("binary");

            Assert.Throws <FormatException>(() => new CellUpdate(col, "this is totally invalid"));
        }
Example #11
0
        public void BoolInvalidFormatTest()
        {
            // If: I create a CellUpdate for a bool column and provide an invalid numeric value
            // Then: It should throw an exception
            DbColumnWrapper col = GetWrapper <bool>("bit");

            Assert.Throws <ArgumentOutOfRangeException>(() => new CellUpdate(col, "12345"));
        }
Example #12
0
        public void StringTooLongTest(string value)
        {
            // If: I attempt to create a CellUpdate to set it to a large string
            // Then: I should get an exception thrown
            DbColumnWrapper col = GetWrapper <string>("nvarchar", false, 6);

            Assert.Throws <FormatException>(() => new CellUpdate(col, value));
        }
Example #13
0
 private DbColumnWrapper[] CreateColumnWrappers(string[] colNames)
 {
     DbColumnWrapper[] cols = new DbColumnWrapper[colNames.Length];
     for (int i = 0; i < cols.Length; i++)
     {
         cols[i] = new DbColumnWrapper(new TestDbColumn(colNames[i], i));
     }
     return(cols);
 }
Example #14
0
        /// <summary>
        /// Constructs a new cell update based on the the string value provided and the column
        /// for the cell.
        /// </summary>
        /// <param name="column">Column the cell will be under</param>
        /// <param name="valueAsString">The string from the client to convert to an object</param>
        public CellUpdate(DbColumnWrapper column, string valueAsString)
        {
            Validate.IsNotNull(nameof(column), column);
            Validate.IsNotNull(nameof(valueAsString), valueAsString);

            // Store the state that won't be changed
            Column = column;
            Type columnType = column.DataType;

            // Check for null
            if (valueAsString == NullString)
            {
                ProcessNullValue();
            }
            else if (columnType == typeof(byte[]))
            {
                // Binary columns need special attention
                ProcessBinaryCell(valueAsString);
            }
            else if (columnType == typeof(string))
            {
                // Special case for strings because the string value should stay the same as provided
                // If user typed 'NULL' they mean NULL as text
                Value         = valueAsString == TextNullString ? NullString : valueAsString;
                ValueAsString = valueAsString;
            }
            else if (columnType == typeof(Guid))
            {
                Value         = Guid.Parse(valueAsString);
                ValueAsString = Value.ToString();
            }
            else if (columnType == typeof(TimeSpan))
            {
                ProcessTimespanColumn(valueAsString);
            }
            else if (columnType == typeof(DateTimeOffset))
            {
                Value         = DateTimeOffset.Parse(valueAsString, CultureInfo.CurrentCulture);
                ValueAsString = Value.ToString();
            }
            else if (columnType == typeof(bool))
            {
                ProcessBooleanCell(valueAsString);
            }
            // @TODO: Microsoft.SqlServer.Types.SqlHierarchyId
            else
            {
                // Attempt to go straight to the destination type, if we know what it is, otherwise
                // leave it as a string
                Value = columnType != null
                    ? Convert.ChangeType(valueAsString, columnType, CultureInfo.CurrentCulture)
                    : valueAsString;

                ValueAsString = Value.ToString();
            }
        }
        private IList <DbColumnWrapper> MapColumns(ColumnInfo[] columns)
        {
            List <DbColumnWrapper> columnWrappers = new List <DbColumnWrapper>();

            foreach (ColumnInfo column in columns)
            {
                DbColumnWrapper wrapper = new DbColumnWrapper(column);
                columnWrappers.Add(wrapper);
            }
            return(columnWrappers);
        }
Example #16
0
        public void ByteArrayTest(string strValue, byte[] expectedValue, string expectedString)
        {
            // If: I attempt to create a CellUpdate for a binary column
            DbColumnWrapper col = GetWrapper <byte[]>("binary");
            CellUpdate      cu  = new CellUpdate(col, strValue);

            // Then: The value should be a binary and should match the expected data
            Assert.IsType <byte[]>(cu.Value);
            Assert.Equal(expectedValue, cu.Value);
            Assert.Equal(expectedString, cu.ValueAsString);
            Assert.Equal(col, cu.Column);
        }
Example #17
0
        public void NullTextStringTest()
        {
            // If: I attempt to create a CellUpdate with the text 'NULL' (with mixed case)
            DbColumnWrapper col = GetWrapper <string>("ntext");
            CellUpdate      cu  = new CellUpdate(col, "'NULL'");

            // Then: The value should be NULL
            Assert.IsType <string>(cu.Value);
            Assert.Equal("NULL", cu.Value);
            Assert.Equal("'NULL'", cu.ValueAsString);
            Assert.Equal(col, cu.Column);
        }
Example #18
0
        public void BoolTest(string input, bool output, string outputString)
        {
            // If: I attempt to create a CellUpdate for a boolean column
            DbColumnWrapper col = GetWrapper <bool>("bit");
            CellUpdate      cu  = new CellUpdate(col, input);

            // Then: The value should match what was expected
            Assert.IsType <bool>(cu.Value);
            Assert.Equal(output, cu.Value);
            Assert.Equal(outputString, cu.ValueAsString);
            Assert.Equal(col, cu.Column);
        }
Example #19
0
        /// <summary>
        /// Generates a command that can be executed to insert a new row -- and return the newly
        /// inserted row.
        /// </summary>
        /// <param name="connection">The connection the command should be associated with</param>
        /// <returns>Command to insert the new row</returns>
        public override DbCommand GetCommand(DbConnection connection)
        {
            Validate.IsNotNull(nameof(connection), connection);

            // Process all the columns. Add the column to the output columns, add updateable
            // columns to the input parameters
            List <string> outColumns = new List <string>();
            List <string> inColumns  = new List <string>();
            DbCommand     command    = connection.CreateCommand();

            for (int i = 0; i < AssociatedResultSet.Columns.Length; i++)
            {
                DbColumnWrapper column = AssociatedResultSet.Columns[i];
                CellUpdate      cell   = newCells[i];

                // Add the column to the output
                outColumns.Add($"inserted.{SqlScriptFormatter.FormatIdentifier(column.ColumnName)}");

                // Skip columns that cannot be updated
                if (!column.IsUpdatable)
                {
                    continue;
                }

                // If we're missing a cell, then we cannot continue
                if (cell == null)
                {
                    throw new InvalidOperationException(SR.EditDataCreateScriptMissingValue);
                }

                // Create a parameter for the value and add it to the command
                // Add the parameterization to the list and add it to the command
                string paramName = $"@Value{RowId}{i}";
                inColumns.Add(paramName);
                SqlParameter param = new SqlParameter(paramName, cell.Column.SqlDbType)
                {
                    Value = cell.Value
                };
                command.Parameters.Add(param);
            }
            string joinedInColumns  = string.Join(", ", inColumns);
            string joinedOutColumns = string.Join(", ", outColumns);

            // Get the start clause
            string start = GetTableClause();

            // Put the whole #! together
            command.CommandText = string.Format(InsertCompleteOutput, start, joinedOutColumns, joinedInColumns);
            command.CommandType = CommandType.Text;

            return(command);
        }
Example #20
0
        public void RoundTripTest(DbColumnWrapper col, object obj)
        {
            // Setup: Figure out the test string
            string testString = obj.ToString();

            // If: I attempt to create a CellUpdate
            CellUpdate cu = new CellUpdate(col, testString);

            // Then: The value and type should match what we put in
            Assert.IsType(col.DataType, cu.Value);
            Assert.Equal(obj, cu.Value);
            Assert.Equal(testString, cu.ValueAsString);
            Assert.Equal(col, cu.Column);
        }
Example #21
0
        public void NullStringAllowedTest()
        {
            // If: I attempt to create a CellUpdate to set it to NULL
            const string    nullString = "NULL";
            DbColumnWrapper col        = GetWrapper <string>("ntext");
            CellUpdate      cu         = new CellUpdate(col, nullString);

            // Then: The value should be a DBNull and the string value should be the same as what
            //       was given
            Assert.IsType <DBNull>(cu.Value);
            Assert.Equal(DBNull.Value, cu.Value);
            Assert.Equal(nullString, cu.ValueAsString);
            Assert.Equal(col, cu.Column);
        }
Example #22
0
        /// <summary>
        /// Performs validation of column ID and if column can be updated.
        /// </summary>
        /// <exception cref="ArgumentOutOfRangeException">
        /// If <paramref name="columnId"/> is less than 0 or greater than the number of columns
        /// in the row
        /// </exception>
        /// <exception cref="InvalidOperationException">If the column is not updatable</exception>
        /// <param name="columnId">Ordinal of the column to update</param>
        protected void ValidateColumnIsUpdatable(int columnId)
        {
            // Sanity check that the column ID is within the range of columns
            if (columnId >= AssociatedResultSet.Columns.Length || columnId < 0)
            {
                throw new ArgumentOutOfRangeException(nameof(columnId), SR.EditDataColumnIdOutOfRange);
            }

            DbColumnWrapper column = AssociatedResultSet.Columns[columnId];

            if (!column.IsUpdatable)
            {
                throw new InvalidOperationException(SR.EditDataColumnCannotBeEdited);
            }
        }
Example #23
0
        /// <summary>
        /// Extracts extended column properties from the database columns from SQL Client
        /// </summary>
        /// <param name="dbColumn">The column information provided by SQL Client</param>
        public void Extend(DbColumnWrapper dbColumn)
        {
            Validate.IsNotNull(nameof(dbColumn), dbColumn);

            DbColumn = dbColumn;

            // A column is trustworthy for uniqueness if it can be updated or it has an identity
            // property. If both of these are false (eg, timestamp) we can't trust it to uniquely
            // identify a row in the table
            IsTrustworthyForUniqueness = dbColumn.IsUpdatable || dbColumn.IsIdentity.HasTrue();

            // A key column is determined by whether it is a key
            IsKey = dbColumn.IsKey;

            // A column is calculated if it is identity, computed, or otherwise not updatable
            IsCalculated = IsIdentity || IsComputed || !dbColumn.IsUpdatable;

            // Mark the column as extended
            HasExtendedProperties = true;
        }
Example #24
0
        public void DateTime2InvalidScaleTest()
        {
            // Setup: Create some test values
            // NOTE: We are doing these here instead of InlineData because DateTime values can't be written as constant expressions
            DateTime[] testValues =
            {
                DateTime.Now, DateTime.UtcNow, DateTime.MinValue, DateTime.MaxValue
            };

            // Setup: Create a DATETIME2 column
            DbColumnWrapper col = new DbColumnWrapper(new TestDbColumn("col", "DaTeTiMe2", 255));

            foreach (DateTime value in testValues)
            {
                string displayValue = VerifyReadWrite(sizeof(long) + 1, value, (writer, val) => writer.WriteDateTime(val), reader => reader.ReadDateTime(0, col));

                // Make sure the display value has a time string with 7 milliseconds
                Assert.True(Regex.IsMatch(displayValue, @"^[\d]{4}-[\d]{2}-[\d]{2} [\d]{2}:[\d]{2}:[\d]{2}\.[\d]{7}$"));
            }
        }
        /// <summary>
        /// Reads a DateTime from the file at the offset provided
        /// </summary>
        /// <param name="offset">Offset into the file to read the DateTime from</param>
        /// <param name="rowId">Internal ID of the row that will be stored in the cell</param>
        /// <param name="col">Column metadata, used for determining what precision to output</param>
        /// <returns>A DateTime</returns>
        internal FileStreamReadResult ReadDateTime(long offset, long rowId, DbColumnWrapper col)
        {
            return(ReadCellHelper(offset, rowId, length =>
            {
                long ticks = BitConverter.ToInt64(buffer, 0);
                return new DateTime(ticks);
            }, null, dt =>
            {
                // Switch based on the type of column
                string formatString;
                if (col.DataTypeName.Equals("DATE", StringComparison.OrdinalIgnoreCase))
                {
                    // DATE columns should only show the date
                    formatString = DateFormatString;
                }
                else if (col.DataTypeName.StartsWith("DATETIME", StringComparison.OrdinalIgnoreCase))
                {
                    // DATETIME and DATETIME2 columns should show date, time, and a variable number
                    // of milliseconds (for DATETIME, it is fixed at 3, but returned as null)
                    // If for some strange reason a scale > 7 is sent, we will cap it at 7 to avoid
                    // an exception from invalid date/time formatting
                    int scale = Math.Min(col.NumericScale ?? 3, 7);
                    formatString = $"{DateFormatString} {TimeFormatString}";
                    if (scale > 0)
                    {
                        string millisecondString = new string('f', scale);
                        formatString += $".{millisecondString}";
                    }
                }
                else
                {
                    // For anything else that returns as a CLR DateTime, just show date and time
                    formatString = $"{DateFormatString} {TimeFormatString}";
                }

                return dt.ToString(formatString);
            }));
        }
Example #26
0
        public void DateTest()
        {
            // Setup: Create some test values
            // NOTE: We are doing these here instead of InlineData because DateTime values can't be written as constant expressions
            DateTime[] testValues =
            {
                DateTime.Now, DateTime.UtcNow, DateTime.MinValue, DateTime.MaxValue
            };

            // Setup: Create a DATE column
            DbColumnWrapper col = new DbColumnWrapper(new TestDbColumn {
                DataTypeName = "DaTe"
            });

            foreach (DateTime value in testValues)
            {
                string displayValue = VerifyReadWrite(sizeof(long) + 1, value, (writer, val) => writer.WriteDateTime(val),
                                                      (reader, rowId) => reader.ReadDateTime(0, rowId, col));

                // Make sure the display value does not have a time string
                Assert.True(Regex.IsMatch(displayValue, @"^[\d]{4}-[\d]{2}-[\d]{2}$"));
            }
        }
Example #27
0
        /// <summary>
        /// Verifies the column and cell, ensuring a column that needs a value has one.
        /// </summary>
        /// <param name="column">Column that will be inserted into</param>
        /// <param name="cell">Current cell value for this row</param>
        /// <param name="defaultCell">Default value for the column in this row</param>
        /// <exception cref="InvalidOperationException">
        /// Thrown if the column needs a value but it is not provided
        /// </exception>
        /// <returns>
        /// <c>true</c> If the column has a value provided
        /// <c>false</c> If the column does not have a value provided (column is read-only, has default, etc)
        /// </returns>
        private static bool IsCellValueProvided(DbColumnWrapper column, CellUpdate cell, string defaultCell)
        {
            // Skip columns that cannot be updated
            if (!column.IsUpdatable)
            {
                return(false);
            }

            // Make sure a value was provided for the cell
            if (cell == null)
            {
                // If the column is not nullable and there is not default defined, then fail
                if (!column.AllowDBNull.HasTrue() && defaultCell == null)
                {
                    throw new InvalidOperationException(SR.EditDataCreateScriptMissingValue(column.ColumnName));
                }

                // There is a default value (or omitting the value is fine), so trust the db will apply it correctly
                return(false);
            }

            return(true);
        }
        /// <summary>
        /// Writes an entire row to the file stream
        /// </summary>
        /// <param name="reader">A primed reader</param>
        /// <returns>Number of bytes used to write the row</returns>
        public int WriteRow(StorageDataReader reader)
        {
            // Read the values in from the db
            object[] values = new object[reader.Columns.Length];
            if (!reader.HasLongColumns)
            {
                // get all record values in one shot if there are no extra long fields
                reader.GetValues(values);
            }

            // Loop over all the columns and write the values to the temp file
            int rowBytes = 0;

            for (int i = 0; i < reader.Columns.Length; i++)
            {
                DbColumnWrapper ci = reader.Columns[i];
                if (reader.HasLongColumns)
                {
                    if (reader.IsDBNull(i))
                    {
                        // Need special case for DBNull because
                        // reader.GetValue doesn't return DBNull in case of SqlXml and CLR type
                        values[i] = DBNull.Value;
                    }
                    else
                    {
                        if (!ci.IsLong)
                        {
                            // not a long field
                            values[i] = reader.GetValue(i);
                        }
                        else
                        {
                            // this is a long field
                            if (ci.IsBytes)
                            {
                                values[i] = reader.GetBytesWithMaxCapacity(i, maxCharsToStore);
                            }
                            else if (ci.IsChars)
                            {
                                Debug.Assert(maxCharsToStore > 0);
                                values[i] = reader.GetCharsWithMaxCapacity(i,
                                                                           ci.IsXml ? maxXmlCharsToStore : maxCharsToStore);
                            }
                            else if (ci.IsXml)
                            {
                                Debug.Assert(maxXmlCharsToStore > 0);
                                values[i] = reader.GetXmlWithMaxCapacity(i, maxXmlCharsToStore);
                            }
                            else
                            {
                                // we should never get here
                                Debug.Assert(false);
                            }
                        }
                    }
                }

                // Get true type of the object
                Type tVal = values[i].GetType();

                // Write the object to a file
                if (tVal == typeof(DBNull))
                {
                    rowBytes += WriteNull();
                }
                else
                {
                    if (ci.IsSqlVariant)
                    {
                        // serialize type information as a string before the value
                        string val = tVal.ToString();
                        rowBytes += WriteString(val);
                    }

                    // Use the appropriate writing method for the type
                    Func <object, int> writeMethod;
                    if (writeMethods.TryGetValue(tVal, out writeMethod))
                    {
                        rowBytes += writeMethod(values[i]);
                    }
                    else
                    {
                        rowBytes += WriteString(values[i].ToString());
                    }
                }
            }

            // Flush the buffer after every row
            FlushBuffer();
            return(rowBytes);
        }
Example #29
0
        /// <summary>
        /// Constructs a new cell update based on the the string value provided and the column
        /// for the cell.
        /// </summary>
        /// <param name="column">Column the cell will be under</param>
        /// <param name="valueAsString">The string from the client to convert to an object</param>
        public CellUpdate(DbColumnWrapper column, string valueAsString)
        {
            Validate.IsNotNull(nameof(column), column);
            Validate.IsNotNull(nameof(valueAsString), valueAsString);

            // Store the state that won't be changed
            try
            {
                Column = column;
                Type columnType = column.DataType;

                // Check for null
                if (valueAsString == NullString)
                {
                    ProcessNullValue();
                }
                else if (columnType == typeof(byte[]))
                {
                    // Binary columns need special attention
                    ProcessBinaryCell(valueAsString);
                }
                else if (columnType == typeof(string))
                {
                    ProcessTextCell(valueAsString);
                }
                else if (columnType == typeof(Guid))
                {
                    Value         = Guid.Parse(valueAsString);
                    ValueAsString = Value.ToString();
                }
                else if (columnType == typeof(TimeSpan))
                {
                    ProcessTimespanColumn(valueAsString);
                }
                else if (columnType == typeof(DateTimeOffset))
                {
                    Value         = DateTimeOffset.Parse(valueAsString, CultureInfo.CurrentCulture);
                    ValueAsString = Value.ToString();
                }
                else if (columnType == typeof(bool))
                {
                    ProcessBooleanCell(valueAsString);
                }
                // @TODO: Microsoft.SqlServer.Types.SqlHierarchyId
                else
                {
                    // Attempt to go straight to the destination type, if we know what it is, otherwise
                    // leave it as a string
                    Value = columnType != null
                        ? Convert.ChangeType(valueAsString, columnType, CultureInfo.CurrentCulture)
                        : valueAsString;

                    ValueAsString = Value.ToString();
                }
            }
            catch (FormatException fe)
            {
                // Pretty up the exception so the user can learn a bit from it
                // NOTE: Other formatting errors raised by helpers are InvalidOperationException to
                //       avoid being prettied here
                throw new FormatException(SR.EditDataInvalidFormat(column.ColumnName, ToSqlScript.FormatColumnType(column)), fe);
            }
        }
        /// <summary>
        /// Generates an INSERT script that will insert this row
        /// </summary>
        /// <param name="forCommand">
        /// If <c>true</c> the script will be generated with an OUTPUT clause for returning all
        /// values in the inserted row (including computed values). The script will also generate
        /// parameters for inserting the values.
        /// If <c>false</c> the script will not have an OUTPUT clause and will have the values
        /// directly inserted into the script (with proper escaping, of course).
        /// </param>
        /// <returns>A script build result object with the script text and any parameters</returns>
        /// <exception cref="InvalidOperationException">
        /// Thrown if there are columns that are not readonly, do not have default values, and were
        /// not assigned values.
        /// </exception>
        private ScriptBuildResult BuildInsertScript(bool forCommand)
        {
            // Process all the columns in this table
            List <string>       inValues      = new List <string>();
            List <string>       inColumns     = new List <string>();
            List <string>       outColumns    = new List <string>();
            List <SqlParameter> sqlParameters = new List <SqlParameter>();

            for (int i = 0; i < AssociatedObjectMetadata.Columns.Length; i++)
            {
                DbColumnWrapper column = AssociatedResultSet.Columns[i];
                CellUpdate      cell   = newCells[i];

                // Add an out column if we're doing this for a command
                if (forCommand)
                {
                    outColumns.Add($"inserted.{SqlScriptFormatter.FormatIdentifier(column.ColumnName)}");
                }

                // Skip columns that cannot be updated
                if (!column.IsUpdatable)
                {
                    continue;
                }

                // Make sure a value was provided for the cell
                if (cell == null)
                {
                    // If the column is not nullable and there is no default defined, then fail
                    if (!column.AllowDBNull.HasTrue() && DefaultValues[i] == null)
                    {
                        throw new InvalidOperationException(SR.EditDataCreateScriptMissingValue(column.ColumnName));
                    }

                    // There is a default value (or omitting the value is fine), so trust the db will apply it correctly
                    continue;
                }

                // Add the input values
                if (forCommand)
                {
                    // Since this script is for command use, add parameter for the input value to the list
                    string paramName = $"@Value{RowId}_{i}";
                    inValues.Add(paramName);

                    SqlParameter param = new SqlParameter(paramName, cell.Column.SqlDbType)
                    {
                        Value = cell.Value
                    };
                    sqlParameters.Add(param);
                }
                else
                {
                    // This script isn't for command use, add the value, formatted for insertion
                    inValues.Add(SqlScriptFormatter.FormatValue(cell.Value, column));
                }

                // Add the column to the in columns
                inColumns.Add(SqlScriptFormatter.FormatIdentifier(column.ColumnName));
            }

            // Begin the script (ie, INSERT INTO blah)
            StringBuilder queryBuilder = new StringBuilder();

            queryBuilder.AppendFormat(InsertScriptStart, AssociatedObjectMetadata.EscapedMultipartName);

            // Add the input columns (if there are any)
            if (inColumns.Count > 0)
            {
                string joinedInColumns = string.Join(", ", inColumns);
                queryBuilder.AppendFormat(InsertScriptColumns, joinedInColumns);
            }

            // Add the output columns (this will be empty if we are not building for command)
            if (outColumns.Count > 0)
            {
                string joinedOutColumns = string.Join(", ", outColumns);
                queryBuilder.AppendFormat(InsertScriptOut, joinedOutColumns);
            }

            // Add the input values (if there any) or use the default values
            if (inValues.Count > 0)
            {
                string joinedInValues = string.Join(", ", inValues);
                queryBuilder.AppendFormat(InsertScriptValues, joinedInValues);
            }
            else
            {
                queryBuilder.AppendFormat(InsertScriptDefault);
            }

            return(new ScriptBuildResult
            {
                ScriptText = queryBuilder.ToString(),
                ScriptParameters = sqlParameters.ToArray()
            });
        }