Welcome to MSDN Blogs Sign in | Join | Help

Displaying varbinary columns in DataGridView

I recently wrote a simple program for displaying SQL query results in a DataGridView, but noticed it was crashing on varbinary columns.  After much searching on the internet, I found out that the default format for a varbinary column is to display it as an image.  While that seems like a fine default, there is no way to change it.  I found a few examples of how to override, but they seemed awfully complicated, especially since I was binding to a dynamic dataset.

Here is a super simple way to handle this scenario:

  1. Extend the DataGridViewColumn class that just stores original the varbinary column
  2. Implement the ColumnAdded event to hide the original varbinary column, and add your extended column to the DataSet
  3. Implement the CellFormatting event and set the value in the format you want

Example:

        class VirtualDataGridViewColumn : DataGridViewColumn
        {
            private DataGridViewColumn originalColumn;

            public VirtualDataGridViewColumn(DataGridViewColumn originalColumn)
                : base()
            {
                this.originalColumn = originalColumn;
            }

            public DataGridViewColumn OriginalColumn
            {
                get { return this.originalColumn; }
            }
        }
   
        private void dataGridView_ColumnAdded(Object sender, DataGridViewColumnEventArgs e)
        {
            if (e.Column.ValueType == typeof(byte[]))
            {
                DataGridViewColumn column = new VirtualDataGridViewColumn(e.Column);
                column.ValueType = typeof(string);
                column.Name = e.Column.Name;
                column.DisplayIndex = e.Column.DisplayIndex;
                column.CellTemplate = new DataGridViewTextBoxCell();
                column.DataPropertyName = e.Column.DataPropertyName;
                column.SortMode = DataGridViewColumnSortMode.Programmatic;

                e.Column.DataGridView.Columns.Add(column);
                e.Column.Visible = false;
            }
        }

        private void dataGridView_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
        {
            DataGridView currentDataGridView = sender as DataGridView;
            if (currentDataGridView.Columns[e.ColumnIndex] is VirtualDataGridViewColumn)
            {
                VirtualDataGridViewColumn column = currentDataGridView.Columns[e.ColumnIndex] as VirtualDataGridViewColumn;
                DataRow dataRow = (currentDataGridView.Rows[e.RowIndex].DataBoundItem as DataRowView).Row;
                e.Value = dataRow[column.OriginalColumn.Name];
            }

            if (e.Value is byte[])
            {
                e.Value = "0x" + BitConverter.ToString(e.Value as byte[]).Replace("-", "");
                e.FormattingApplied = true;
            }
        }

Posted by sferg | 1 Comments

Preventing SQL Injection with Parameters: Caveats

I learned something interesting about SQL parameters today.  In my C# code I was passing a comma separated string as a parameter to a stored procedure using SqlParameter, but it was allowing ' through unchecked causing havoc in the stored procedure.  It turns out when you use dynamic SQL in the stored procedure you lose the safety of the parameter.

Pseudocode Example:

CREATE PROCEDURE [dbo].[CommaSeparatedNames]

@Names NVARCHAR(MAX)

AS

BEGIN

DECLARE @Name NVARCHAR(MAX)

DECLARE @NameQuery NVARCHAR(MAX) SET @NameQuery = 'SELECT * FROM Names WHERE '

-- Split @Names into a @Name, such that

-- each name is wrapped, @NameQuery = @NameQuery + ' Name LIKE ''' + @Name + ''' OR '

-- generating a query like SELECT * FROM Names WHERE Name LIKE 'bob' OR Name LIKE 'john'

EXECUTE sp_executesql @NameQuery

END

When a name was passed with ' in it, the query generation fails.  I have to explicity replace the ' with '' in the C#.

Posted by sferg | 1 Comments

How to pass an array of binary values in SQL Server 2005?

I have a stored procedure that expects an array of binary values.  I'm currently passing it as a comma separate string but I think that is a horrible hack.  I tried using XML, but that didn't seem to work, but it's very possible I could have been doing it wrong.

 How does everyone else pass an array of binary values to stored procedures?

Posted by sferg | 1 Comments

Database table naming conventions

I was recently adding some tables to a database, and was presented with the silly problem of naming a table "User" or "Users."  To me the table name should represent the entity, but on the flip side the table is holding a collection of those entities.

 Since I'm open to suggestion, what are your thoughts on table naming?

Posted by sferg | 5 Comments

Best way to manage database abstraction for development?

The database we are coding for isn't well suited for making quick changes while doing index or query optimization, so I trying to find a good way to swap out the data abstraction layer cleanly to use a different database backend.

 Does anyone have any good examples of easily swapping data access layers?

 Example:

ClassA instantiates a DBQuery class to execute queries.  I would like to replace DBQuery with a DB2Query class which talks to a different database type.  The queries themselves will be the same, it's just the underlying API for communicating with the DB that is different.

I considered using reflection to determine a class to use on the fly, but I really want the solution to be performant and elegant.

Posted by sferg | 1 Comments

SQL Full Text, Word Breakers & You

The other day was a SQL learning adventure.  A team member was trying to find the phrase "Q&A" using the search functionality of our product, but found no results.  They were surprised at this considering they had proof the phrase should have been returned.  Lucky me got tasked with investigating this issue.  This search was just running a contains query against a table in SQL Server 2005.  I figured it was probably something silly our application was doing, so I ran the query directly on the database.  Surprisingly, there were no results returned.

The next step was to try and create a simple repro.  I created a new table, setup full text, and inserted "Q&A" as the only record.  Sure enough, the contains query returned no results.  At this point I was suspecting the "&" so I tried querying for "QA" thinking maybe it was filtering the "&" out.  Again, no results.  Being somewhat knowledgeable about full text, I suspected the word breaker was causing the problem. 

The word breaker takes the incoming text and breaks it up into logical words for indexing.  For example, "blogs rule" would be broken up into two words, "blogs" and "rule."  You would expect the phrase "Q&A" not to be broken up, but in fact it is.  The word breaker returns "Q" and "A," both of which are noise words causing nothing to be indexed. 

So after the lesson in word breakers, I was left with the unfortunate ending of resolving the bug as "By Design."  Maybe next month I can detail the workaround I found.

Posted by sferg | 0 Comments

Lessons in Binary

I recently had an interesting experience with the varbinary column in SQL Server. 

Here was my problem:

I was inserting 0x012 into a varbinary column with the expectation that is what would be stored.  Perhaps taking into consideration byte alignment it would pad a 0 at the end, i.e 0x0120. Boy was I wrong.  The value was stored as 0x0102.  Since my input value was 1.5 bytes, SQL Server padded the value to make it a full 2 bytes by prepending a 0 to the last 4 bits to make a full byte.  That is a completely different value than what I was intending during the insert.  After some chatting with some people in the SQL organization I finally realized why SQL Server treats it as 0x0102 instead of 0x0120.  As humans, we tend to think of things that end with 0 as a bigger number but in the binary world 0x01 is the same as 0x0100.  

 From now on I'll be sure to pad my varbinary values to ensure my intent is preserved.  :)

Posted by sferg | 1 Comments
Filed under:

Calculating SQL Server Index Size

Today I was trying to calculate the size of a specific index in SQL Server and realized it's not obvious to calculate.  I poked around Management Studio and was able to get the size of all indexes for a table, but not for a single index.  Thinking I must have just missed something obvious, I did a quick Live (and then Google) search and didn't get any useful results.  Frustrated, I started digging into the documentation and came upon this handy dynamic management view: sys.dm_db_index_physical_stats.  It provides enough information that you can calculate the size of the index.

Here is the handy stored procedure I wrote to calculate the size of an index in bytes:

CREATE PROCEDURE [dbo].[IndexSize]

      @TableName NVARCHAR(256),

      @IndexName VARCHAR(256)

AS

BEGIN

      DECLARE @index_id INT

      DECLARE @index_size BIGINT SET @index_size = 0

 

      SELECT @index_id = index_id FROM sys.indexes WHERE object_id = OBJECT_ID(@TableName) AND name = @IndexName

 

      SELECT

            @index_size = @index_size + (avg_record_size_in_bytes * record_count)

      FROM sys.dm_db_index_physical_stats (DB_ID(), OBJECT_ID(@TableName), @index_id , NULL, 'DETAILED')

 

      SELECT @index_size as IndexSizeBytes

END

Posted by sferg | 1 Comments
Filed under:

My first MSDN Blog!

I was encouraged by my manager to start blogging, so here I am.  I hope to keep this up to date with tidbits of information I learn throughout my adventures here at Microsoft.

Posted by sferg | 2 Comments
 
Page view tracker