Please start any new threads on our new site at https://forums.sqlteam.com. We've got lots of great SQL Server experts to answer whatever question you can come up with.

 All Forums
 General SQL Server Forums
 Script Library
 BinaryUtilities: CLR Aggregate functions and TVF

Author  Topic 

Arnold Fribble
Yak-finder General

1961 Posts

Posted - 2006-01-30 : 15:25:37
Something a little different: C# on SQLTeam!

It's basically just cobbled together using the aggregate function and TVF in the StringUtilities sample as a starting point.
Er, sorry MS, I forgot to change the namespace from Microsoft.Samples.SqlServer.


/*
Aggregate functions: UnionBinary, IntersectBinary
Table-valued function: SplitBinary
*/

using System;
using System.IO;
using System.Data;
using System.Data.Sql;
using System.Data.SqlTypes;
using System.Text;
using System.Collections;
using System.Collections.Generic;
using Microsoft.SqlServer.Server;

[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design",
"CA1020:AvoidNamespacesWithFewTypes", Scope = "namespace",
Target = "Microsoft.Samples.SqlServer")]

namespace Microsoft.Samples.SqlServer
{
[Serializable]
[Microsoft.SqlServer.Server.SqlUserDefinedAggregate(
Microsoft.SqlServer.Server.Format.UserDefined,
IsInvariantToNulls = true,
IsInvariantToDuplicates = true,
IsInvariantToOrder = true,
MaxByteSize = 4100)
]
public class UnionBinary : Microsoft.SqlServer.Server.IBinarySerialize
{
private byte[] bitset;

public void Init() { bitset = new byte[4]; }

public void Accumulate(SqlInt16 value)
{
if (!value.IsNull && value.Value >= 0) {
if (bitset.Length <= value.Value / 8) {
Array.Resize(ref bitset, (value.Value/32 + 1) * 4);
}
bitset[value.Value / 8] |=
System.Convert.ToByte(1 << (value.Value % 8));
}
}

public void Merge(UnionBinary other)
{
if (other.bitset.Length > bitset.Length) {
Array.Resize(ref bitset, other.bitset.Length);
}
for (int i = 0; i < bitset.Length; i++) {
bitset[i] |= other.bitset[i];
}
}

public SqlBinary Terminate() { return new SqlBinary(bitset); }

public void Read(BinaryReader r)
{
int i = r.ReadInt32();
bitset = r.ReadBytes(i);
}

public void Write(BinaryWriter w) {
w.Write(bitset.Length);
w.Write(bitset);
}
}

[Serializable]
[Microsoft.SqlServer.Server.SqlUserDefinedAggregate(
Microsoft.SqlServer.Server.Format.UserDefined,
IsInvariantToNulls = true,
IsInvariantToDuplicates = true,
IsInvariantToOrder = true,
MaxByteSize = 4100)
]
public class IntersectBinary : Microsoft.SqlServer.Server.IBinarySerialize
{
private byte[] bitset;

public void Init() { bitset = new byte[4]; }

public void Accumulate(SqlInt16 value)
{
if (!value.IsNull && value.Value >= 0) {
if (bitset.Length <= value.Value / 8) {
Array.Resize(ref bitset, (value.Value/32 + 1) * 4);
}
bitset[value.Value / 8] &=
System.Convert.ToByte(1 << (value.Value % 8));
}
}

public void Merge(IntersectBinary other)
{
if (other.bitset.Length > bitset.Length) {
Array.Resize(ref bitset, other.bitset.Length);
}
for (int i = 0; i < bitset.Length; i++) {
bitset[i] &= other.bitset[i];
}
}

public SqlBinary Terminate() { return new SqlBinary(bitset); }

public void Read(BinaryReader r)
{
int i = r.ReadInt32();
bitset = r.ReadBytes(i);
}

public void Write(BinaryWriter w) {
w.Write(bitset.Length);
w.Write(bitset);
}
}

public sealed class SplitBinaryCls
{
[SqlFunction(FillRowMethodName = "FillRow")]
public static IEnumerable SplitBinary(SqlBinary argument)
{
List<Int16> r = new List<Int16>();
if (!argument.IsNull) {
for (int i = 0; i < argument.Length; i++) {
for (int j = 0; j < 8; j++) {
if ((argument.Value[i] & Convert.ToByte(1 << j)) != 0) {
r.Add(Convert.ToInt16(i*8+j));
}
}
}
}
return r;
}

[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design",
"CA1021:AvoidOutParameters")]
public static void FillRow(Object obj, out Int16 stringElement)
{
stringElement = (Int16)obj;
}

private SplitBinaryCls() { }
}
}


To install the compiled dll something like:

CREATE ASSEMBLY BinaryUtilities
FROM 'C:\...\BinaryUtilities\bin\debug\BinaryUtilities.dll'
WITH permission_set=Safe;
GO

CREATE AGGREGATE UnionBinary(@input smallint)
RETURNS varbinary(4096)
EXTERNAL NAME [BinaryUtilities].[Microsoft.Samples.SqlServer.UnionBinary];
GO
CREATE AGGREGATE IntersectBinary(@input smallint)
RETURNS varbinary(4096)
EXTERNAL NAME [BinaryUtilities].[Microsoft.Samples.SqlServer.IntersectBinary];
GO
CREATE FUNCTION SplitBinary(@input varbinary(4096))
RETURNS TABLE(ix smallint)
AS EXTERNAL NAME [BinaryUtilities].[Microsoft.Samples.SqlServer.SplitBinaryCls].[SplitBinary];
GO

Michael Valentine Jones
Yak DBA Kernel (pronounced Colonel)

7020 Posts

Posted - 2006-01-30 : 18:22:31
So what do they do?

CODO ERGO SUM
Go to Top of Page

Arnold Fribble
Yak-finder General

1961 Posts

Posted - 2006-01-31 : 02:54:42
Sheesh, isn't that obvious?

UnionBinary aggregates non-negative smallints into a varbinary result where the presence of a value in any row is represented by a corresponding 1 bit in the aggregate value.

IntersectBinary aggregates non-negative smallints into a varbinary result where the presence of a value in all rows is represented by a corresponding 1 bit in the aggregate value. Probably not as useful, but it was only a matter of changing a | to a &.

SplitBinary generates a table of smallints from a varbinary value, returning one row for each 1 bit in the input value.

See here for a use http://www.sqlteam.com/forums/topic.asp?TOPIC_ID=60966
Go to Top of Page
   

- Advertisement -