Question

I have a table which has a column named Permission(binary(8)) whose every bit represents a specific operation permission. In silverlight client I use BitArrary and const integers to manage the permissions and it goes smoothly. The client codes like this:

 public class StaffBase : INotifyPropertyChanged
{
    public const int
        OPERATION_A = 0,
        OPERATION_B = 1,
        // ...
        // OPERATION_I=i,
        // ...
        OPERATION_63 = 63;

    BitArray permission = null;
    public BitArray Permission 
    {
        get { return permission; }
        set 
        {
            if (permission != value)
            {
                permission = value;
                OnPropertyChanged("Permission");
            }
        }
    }

    bool TestPermission(int permissionName)
    {
        return permission != null && permission[permissionName];
    }

    /* 
     Other code segments
     */
}

Now the problem is that I must test permission in stored procedure and unfortunately I am a bit new hand as to SQL. I had set at client side a permission with 2^10, like this:

permission[10]=true;

And I thought I would get a value of 1024 into the column Permission in database. But in fact the column value is 0x0004000000000000. It seems that different storage strategies for byte[] are respectively taken by SQL and .NET. Now I am seeking a method to detect cetern bit of Permission column. I tried to use such clause:

Permission & power(2,i) > 0

It works not right. And there is an anthoer problem: if I want to test the 63th bit, the power(2,63) overflows. Now I hope some sql masters would give me a guidance.

Was it helpful?

Solution

BitArray writes the various bits in order as if you were reading, ie. the first bit is bit-7 of the first byte, the eight bit is bit-0 of the first byte, the 9th bit is bit-7 of the second byte etc. So the minimal solution is that you have to invert the bitness (instead of power(2, i), do power(2, 64 - i). Of course, as you've observed, this is very limited. One option, that will work up to your 64 bits, is to simply use a bigger data type - bigint. However, for anything larger than 64 bits, you're back where you started.

For a more general solution, you want to use the binary field on a per-byte basis. You can use the substring function for this.

select 
  substring(binaryValue, ceiling(cast(@bit as decimal) / 8), 1) 
  & power(2, @bit % 8);

This gives you a zero if the specified bit is not set, and a non-zero value if it is.

The key here is that the string functions actually work for binary / image as well, so you can eg. access any byte at will just by using substring :)

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top