Showing posts with label aggregate. Show all posts
Showing posts with label aggregate. Show all posts

Monday, March 19, 2012

CLR User-defined aggregate support Java/J#?

I want to write a Java User-defined aggregate (UDA). Shall I use J#?

I converted the C# example given in books online to J#. I am getting this error (as well as whole bunch of warning when I create the assembly.)

Msg 6558, Level 16, State 1, Line 1

CREATE AGGREGATE failed because type 'Concatenate' does not conform to UDAGG specification due to method 'Init'.

Msg 6597, Level 16, State 2, Line 1

CREATE AGGREGATE failed.

btw, I have the use unsafe assembly options when creating the assembly otherwise I get this error:

Msg 6265, Level 16, State 1, Line 1

CREATE ASSEMBLY failed because type "com.ms.vjsharp.cor.COMUtils" in safe assembly "vjscor" has a pinvokeimpl method. P/Invoke is not allowed in safe assemblies.

Warning: The Microsoft .Net frameworks assembly 'vjscor, version=2.0.0.0, culture=neutral, publickeytoken=b03f5f7f11d50a3a, processorarchitecture=x86.' you are registering is not fully tested in SQL Server hosted environment.

From the warning, I can tell the J# UDA is not tested.

Can someone confirm whether J# UDA is supported or not?

Thanks!

-

Here is my code:

ALTER DATABASE MEDIO set TRUSTWORTHY ON

CREATE ASSEMBLY MyAgg FROM 'C:\code\console\PriceUDA\obj\Debug\PriceUDA.dll' WITH PERMISSION_SET = unsafe

CREATE AGGREGATE MyAgg (@.input nvarchar(200)) RETURNS nvarchar(max) EXTERNAL NAME MyAgg.Concatenate

GO

import System.*;

import System.Data.*;

import Microsoft.SqlServer.Server.*;

import System.Data.SqlTypes.*;

import System.IO.*;

import System.Text.*;

/** @.attribute Serializable() */

/** @.attribute SqlUserDefinedAggregate(

Format.UserDefined, //use clr serialization to serialize the intermediate result

IsInvariantToNulls = true, //optimizer property

IsInvariantToDuplicates = false, //optimizer property

IsInvariantToOrder = false, //optimizer property

MaxByteSize = 8000) //maximum size in bytes of persisted value

*/

public class Concatenate implements IBinarySerialize

{

/// <summary>

/// The variable that holds the intermediate result of the concatenation

/// </summary>

private StringBuilder intermediateResult;

/// <summary>

/// Initialize the internal data structures

/// </summary>

public void Init()

{

this.intermediateResult = new StringBuilder();

}

/// <summary>

/// Accumulate the next value, not if the value is null

/// </summary>

/// <param name="value"></param>

public void Accumulate(SqlString value)

{

if (value.get_IsNull())

{

return;

}

this.intermediateResult.Append(value.get_Value()).Append(',');

}

/// <summary>

/// Merge the partially computed aggregate with this aggregate.

/// </summary>

/// <param name="other"></param>

public void Merge(Concatenate other)

{

this.intermediateResult.Append(other.intermediateResult);

}

/// <summary>

/// Called at the end of aggregation, to return the results of the aggregation.

/// </summary>

/// <returns></returns>

public SqlString Terminate()

{

String output = String.Empty;

//delete the trailing comma, if any

if (this.intermediateResult != null

&& this.intermediateResult.get_Length() > 0)

{

output = this.intermediateResult.ToString(0, this.intermediateResult.get_Length() - 1);

}

return new SqlString(output);

}

public void Read(BinaryReader r)

{

intermediateResult = new StringBuilder(r.ReadString());

}

public void Write(BinaryWriter w)

{

w.Write(this.intermediateResult.ToString());

}

}

No responses... Has anyone else been able to get this to work?|||

Hi Chang!

In SQL Server 2005 we support C#, Visual Basic and managed C++ with SQL CLR.

We haven't tested integration with other languages. However, I can imagine that other languages' vendors have tested their languages with SQL CLR, or are going to do this. In this case, they may have published their recommendations on how to use their languages' features with SQL CLR, what problems you may have and so on.

I'm not aware of such recommendations for J#.

|||Vadim -- We are asking about Microsoft J#, not some 3rd party tool.

Microsoft Visual J# is a .net language that uses the CLR. I've seen dozens of quotes that say it 'should work', but I have yet to find anybody who actually got it to work.

I have a bunch of database-neutral java stored procedures, that I recently ported to work with mssql, that I now need to implement as CLR stored procedures. I'd *really* like to port my java to j# using .net, as opposed to porting to c# (Yes, I know about JLCA, I'm working my way throught that now). Unfortunately, Visual Studio 2005 in J# mode has no support for SQL Server, and every document I find on the internet only talks about using VS to generate SQL code. So far, I have not found 1 single example that shows J# running as a CLR stored proc, or what you might have to do to get it to work.|||

Hi!

You are right; I should have phrased this better. Anyway, due to a variety of reasons we haven’t put significant effort into supporting J#. According to my knowledge, you have chances that functions and procedures will work, but you most probably will have problems with user-defined types and aggregates. Have you tried to wrap your J# logic into, say, C# aggregate?

The fact that a language is a .NET language doesn’t automatically mean that it will go well with SQL CLR. The reason is that SQL CLR puts additional restrictions and requirements to the IL code, compared to those necessary just to run IL executable. Not all code generated by .NET compilers satisfies them, not all run-time libraries of these languages satisfy them. I’d guess the way J# compiles classes is not compliant with SQL CLR.

|||

I can't recall the exact problems off the top of my head, but I do recall there being problems with J# in SQL CLR. You may be able to get this working if you register the assembly as UNSAFEan unfortunate move.

I'll see if I can dredge up more.

Cheers,

-Isaac

CLR User-defined aggregate support Java/J#?

I want to write a Java User-defined aggregate (UDA). Shall I use J#?

I converted the C# example given in books online to J#. I am getting this error (as well as whole bunch of warning when I create the assembly.)

Msg 6558, Level 16, State 1, Line 1

CREATE AGGREGATE failed because type 'Concatenate' does not conform to UDAGG specification due to method 'Init'.

Msg 6597, Level 16, State 2, Line 1

CREATE AGGREGATE failed.

btw, I have the use unsafe assembly options when creating the assembly otherwise I get this error:

Msg 6265, Level 16, State 1, Line 1

CREATE ASSEMBLY failed because type "com.ms.vjsharp.cor.COMUtils" in safe assembly "vjscor" has a pinvokeimpl method. P/Invoke is not allowed in safe assemblies.

Warning: The Microsoft .Net frameworks assembly 'vjscor, version=2.0.0.0, culture=neutral, publickeytoken=b03f5f7f11d50a3a, processorarchitecture=x86.' you are registering is not fully tested in SQL Server hosted environment.

From the warning, I can tell the J# UDA is not tested.

Can someone confirm whether J# UDA is supported or not?

Thanks!

-

Here is my code:

ALTER DATABASE MEDIO set TRUSTWORTHY ON

CREATE ASSEMBLY MyAgg FROM 'C:\code\console\PriceUDA\obj\Debug\PriceUDA.dll' WITH PERMISSION_SET = unsafe

CREATE AGGREGATE MyAgg (@.input nvarchar(200)) RETURNS nvarchar(max) EXTERNAL NAME MyAgg.Concatenate

GO

import System.*;

import System.Data.*;

import Microsoft.SqlServer.Server.*;

import System.Data.SqlTypes.*;

import System.IO.*;

import System.Text.*;

/** @.attribute Serializable() */

/** @.attribute SqlUserDefinedAggregate(

Format.UserDefined, //use clr serialization to serialize the intermediate result

IsInvariantToNulls = true, //optimizer property

IsInvariantToDuplicates = false, //optimizer property

IsInvariantToOrder = false, //optimizer property

MaxByteSize = 8000) //maximum size in bytes of persisted value

*/

public class Concatenate implements IBinarySerialize

{

/// <summary>

/// The variable that holds the intermediate result of the concatenation

/// </summary>

private StringBuilder intermediateResult;

/// <summary>

/// Initialize the internal data structures

/// </summary>

public void Init()

{

this.intermediateResult = new StringBuilder();

}

/// <summary>

/// Accumulate the next value, not if the value is null

/// </summary>

/// <param name="value"></param>

public void Accumulate(SqlString value)

{

if (value.get_IsNull())

{

return;

}

this.intermediateResult.Append(value.get_Value()).Append(',');

}

/// <summary>

/// Merge the partially computed aggregate with this aggregate.

/// </summary>

/// <param name="other"></param>

public void Merge(Concatenate other)

{

this.intermediateResult.Append(other.intermediateResult);

}

/// <summary>

/// Called at the end of aggregation, to return the results of the aggregation.

/// </summary>

/// <returns></returns>

public SqlString Terminate()

{

String output = String.Empty;

//delete the trailing comma, if any

if (this.intermediateResult != null

&& this.intermediateResult.get_Length() > 0)

{

output = this.intermediateResult.ToString(0, this.intermediateResult.get_Length() - 1);

}

return new SqlString(output);

}

public void Read(BinaryReader r)

{

intermediateResult = new StringBuilder(r.ReadString());

}

public void Write(BinaryWriter w)

{

w.Write(this.intermediateResult.ToString());

}

}

No responses... Has anyone else been able to get this to work?
|||

Hi Chang!

In SQL Server 2005 we support C#, Visual Basic and managed C++ with SQL CLR.

We haven't tested integration with other languages. However, I can imagine that other languages' vendors have tested their languages with SQL CLR, or are going to do this. In this case, they may have published their recommendations on how to use their languages' features with SQL CLR, what problems you may have and so on.

I'm not aware of such recommendations for J#.

|||Vadim -- We are asking about Microsoft J#, not some 3rd party tool.

Microsoft Visual J# is a .net language that uses the CLR. I've seen dozens of quotes that say it 'should work', but I have yet to find anybody who actually got it to work.

I have a bunch of database-neutral java stored procedures, that I recently ported to work with mssql, that I now need to implement as CLR stored procedures. I'd *really* like to port my java to j# using .net, as opposed to porting to c# (Yes, I know about JLCA, I'm working my way throught that now). Unfortunately, Visual Studio 2005 in J# mode has no support for SQL Server, and every document I find on the internet only talks about using VS to generate SQL code. So far, I have not found 1 single example that shows J# running as a CLR stored proc, or what you might have to do to get it to work.

|||

Hi!

You are right; I should have phrased this better. Anyway, due to a variety of reasons we haven’t put significant effort into supporting J#. According to my knowledge, you have chances that functions and procedures will work, but you most probably will have problems with user-defined types and aggregates. Have you tried to wrap your J# logic into, say, C# aggregate?

The fact that a language is a .NET language doesn’t automatically mean that it will go well with SQL CLR. The reason is that SQL CLR puts additional restrictions and requirements to the IL code, compared to those necessary just to run IL executable. Not all code generated by .NET compilers satisfies them, not all run-time libraries of these languages satisfy them. I’d guess the way J# compiles classes is not compliant with SQL CLR.

|||

I can't recall the exact problems off the top of my head, but I do recall there being problems with J# in SQL CLR. You may be able to get this working if you register the assembly as UNSAFEan unfortunate move.

I'll see if I can dredge up more.

Cheers,

-Isaac

CLR user defined aggregate function (SS2005)

Hello,
In a user defined aggregate in Visual Studio 2005 with SQL Server 2005, I
declared a private variable in the struct and initialized in the Init "event
"
of the aggregate.
In the Terminate "event" it turned out that the variable was out of scope
(null).
My first thought was that this happened as a result of reads and writes of
intermediate results of the aggregate function, where (in my case) the
private variable was not explicitly saved.
But this idea is not consistent with the Merge "event" that also uses the
private variable and there it never is out of scope.
Who can explain?
Thx.examnotes <Axford@.discussions.microsoft.com> wrote in
news:B7150A1D-2067-4377-8483-090BB56A7023@.microsoft.com:

> In a user defined aggregate in Visual Studio 2005 with SQL Server
> 2005, I declared a private variable in the struct and initialized in
> the Init "event" of the aggregate.
> In the Terminate "event" it turned out that the variable was out of
> scope (null).
> My first thought was that this happened as a result of reads and
> writes of intermediate results of the aggregate function, where (in my
> case) the private variable was not explicitly saved.
> But this idea is not consistent with the Merge "event" that also uses
> the private variable and there it never is out of scope.
How do you establish that the variable is not null in the Merge method?
In other words, are you certain that the Merge is being called. SQL will
not call Merge unless it creates a new instance of your aggregate and
runs that instance in parallell over a group in your accumulation.
Anyway, can you please post the code for your aggregate and we'll have a
look.
Also, it'd probably be better is you posted this in the sqlserver.clr
group which deals explicitly with SQLCLR issues. I will x-post this
reply to there.
Niels
****************************************
**********
* Niels Berglund
* http://staff.develop.com/nielsb
* nielsb@.no-spam.develop.com
* "A First Look at SQL Server 2005 for Developers"
* http://www.awprofessional.com/title/0321180593
****************************************
**********|||Sorry it was the Accumulate event where the private variable was in scope. S
o
probably the Merge event will set it to null also. Can I enforce thecall to
Merge in some way?
I cannot find a group sqlserver.clr.
Thanks for the reply.
"Niels Berglund" wrote:

> examnotes <Axford@.discussions.microsoft.com> wrote in
> news:B7150A1D-2067-4377-8483-090BB56A7023@.microsoft.com:
>
>
> How do you establish that the variable is not null in the Merge method?
> In other words, are you certain that the Merge is being called. SQL will
> not call Merge unless it creates a new instance of your aggregate and
> runs that instance in parallell over a group in your accumulation.
> Anyway, can you please post the code for your aggregate and we'll have a
> look.
> Also, it'd probably be better is you posted this in the sqlserver.clr
> group which deals explicitly with SQLCLR issues. I will x-post this
> reply to there.
>
> Niels
> --
> ****************************************
**********
> * Niels Berglund
> * http://staff.develop.com/nielsb
> * nielsb@.no-spam.develop.com
> * "A First Look at SQL Server 2005 for Developers"
> * http://www.awprofessional.com/title/0321180593
> ****************************************
**********
>|||examnotes <Axford@.discussions.microsoft.com> wrote in
news:FC2366AE-AFFD-4AD9-8E03-680568F1C497@.microsoft.com:

> Sorry it was the Accumulate event where the private variable was in
> scope. So probably the Merge event will set it to null also. Can I
> enforce thecall to Merge in some way?
OK, so in Accumulate the variable is OK, but in Terminate it is null -
is that correct? If so, please post the code for your UDA. AFAIK, you
can not force a call for Merge.

> I cannot find a group sqlserver.clr.
Do a refresh of your newsgroup list - that should make it available to
you (microsoft.public.sqlserver.clr).
Niels
****************************************
**********
* Niels Berglund
* http://staff.develop.com/nielsb
* nielsb@.no-spam.develop.com
* "A First Look at SQL Server 2005 for Developers"
* http://www.awprofessional.com/title/0321180593
****************************************
**********|||Here you go with the code (it is from Microsoft samples):
[Serializable]
[Microsoft.SqlServer.Server.SqlUserDefinedAggregate(
Format.UserDefined,MaxByteSize=8000, IsInvariantToNulls=true,
IsInvariantToDuplicates = false, IsInvariantToOrder=true,
IsNullIfEmpty=true)]
public struct Concatenate : IBinarySerialize
{
private string delimeter;
private StringBuilder intermediateResult;
public void Init()
{
delimeter = "-";
intermediateResult = new StringBuilder();
}
public void Accumulate(SqlString value)
{
if (value.IsNull)
return;
intermediateResult.Append(value.Value).Append(delimeter);
}
public void Merge(Concatenate other)
{
intermediateResult.Append(other.intermediateResult).Append(delimeter);
}
public SqlString Terminate()
{
string output = string.Empty;
if (this.intermediateResult != null
&& this.intermediateResult.Length > 0)
{
output = this.intermediateResult.ToString(0,
this.intermediateResult.Length - 1);
}
return new SqlString(output);
}
#region IBinarySerialize Members
void IBinarySerialize.Read(System.IO.BinaryReader r)
{
intermediateResult = new StringBuilder(r.ToString());
}
void IBinarySerialize.Write(System.IO.BinaryWriter w)
{
w.Write(intermediateResult.ToString());
}
#endregion
}
"Niels Berglund" wrote:

> examnotes <Axford@.discussions.microsoft.com> wrote in
> news:FC2366AE-AFFD-4AD9-8E03-680568F1C497@.microsoft.com:
>
> OK, so in Accumulate the variable is OK, but in Terminate it is null -
> is that correct? If so, please post the code for your UDA. AFAIK, you
> can not force a call for Merge.
>
> Do a refresh of your newsgroup list - that should make it available to
> you (microsoft.public.sqlserver.clr).
> Niels
> --
> ****************************************
**********
> * Niels Berglund
> * http://staff.develop.com/nielsb
> * nielsb@.no-spam.develop.com
> * "A First Look at SQL Server 2005 for Developers"
> * http://www.awprofessional.com/title/0321180593
> ****************************************
**********
>

CLR User Defined Aggregate Function

I am trying to modify the C# example given in the "Invoking CLR User-Defined Aggregate Functions" in SQL Server 2005 Books Online. I want to add a parameter that is used as the list delimeter, instead of the hard coded comma that is used. I am not a C# programmer and don't know where to begin. Please help!

using System;
using System.Data;
using Microsoft.SqlServer.Server;
using System.Data.SqlTypes;
using System.IO;
using System.Text;

[Serializable]
[SqlUserDefinedAggregate(
Format.UserDefined, //use clr serialization to serialize the intermediate result
IsInvariantToNulls = true, //optimizer property
IsInvariantToDuplicates = false, //optimizer property
IsInvariantToOrder = false, //optimizer property
MaxByteSize = 8000) //maximum size in bytes of persisted value
]
public class Concatenate : IBinarySerialize
{
/// <summary>
/// The variable that holds the intermediate result of the concatenation
/// </summary>
private StringBuilder intermediateResult;

/// <summary>
/// Initialize the internal data structures
/// </summary>
public void Init()
{
this.intermediateResult = new StringBuilder();
}

/// <summary>
/// Accumulate the next value, not if the value is null
/// </summary>
/// <param name="value"></param>
public void Accumulate(SqlString value)
{
if (value.IsNull)
{
return;
}

this.intermediateResult.Append(value.Value).Append(','); /// I want to change to comma to a variable
}

/// <summary>
/// Merge the partially computed aggregate with this aggregate.
/// </summary>
/// <param name="other"></param>
public void Merge(Concatenate other)
{
this.intermediateResult.Append(other.intermediateResult);
}

/// <summary>
/// Called at the end of aggregation, to return the results of the aggregation.
/// </summary>
/// <returns></returns>
public SqlString Terminate()
{
string output = string.Empty;
//delete the trailing comma, if any
if (this.intermediateResult != null
&& this.intermediateResult.Length > 0)
{
output = this.intermediateResult.ToString(0, this.intermediateResult.Length - 1);
}

return new SqlString(output);
}

public void Read(BinaryReader r)
{
intermediateResult = new StringBuilder(r.ReadString());
}

public void Write(BinaryWriter w)
{
w.Write(this.intermediateResult.ToString());
}
}

Hi Rob,

Unfortunately, a current limitation of our UDAs is that they can only take one parameter: the single parameter being aggregated. This precludes a few scenarios, including an additional parameter that is constant for the life of the aggregate (your situation) as well as a second aggregated parameter.

The usual workaround we recommend for folks who want to aggregate over two variables is to wrap them using either XML or a UDT and then unwrap them inside of the aggregate. This could work in your situation as welljust hold one of the variables constantbut is a particularly ugly hack.

Cheers,

-Isaac

|||Hi Isaac,

Since we're considering ugly hacks, I had an idea for another workaround: could I create a table variable, and access it from within my UDA?

E.g., in the following procedure, I create a temp table with params, which my UDA will expect to find in scope when it runs. I have no idea if this would work at all...

CREATE PROCEDURE foo
AS
DECLARE @.settings table (
param1 int,
param2 char
)

SELECT lastName, dbo.myConcatUDA(firstName)
FROM people
GROUP BY lastName

GO

CLR User Defined Aggregate Function

I am trying to modify the C# example given in the "Invoking CLR User-Defined Aggregate Functions" in SQL Server 2005 Books Online. I want to add a parameter that is used as the list delimeter, instead of the hard coded comma that is used. I am not a C# programmer and don't know where to begin. Please help!

using System;
using System.Data;
using Microsoft.SqlServer.Server;
using System.Data.SqlTypes;
using System.IO;
using System.Text;

[Serializable]
[SqlUserDefinedAggregate(
Format.UserDefined, //use clr serialization to serialize the intermediate result
IsInvariantToNulls = true, //optimizer property
IsInvariantToDuplicates = false, //optimizer property
IsInvariantToOrder = false, //optimizer property
MaxByteSize = 8000) //maximum size in bytes of persisted value
]
public class Concatenate : IBinarySerialize
{
/// <summary>
/// The variable that holds the intermediate result of the concatenation
/// </summary>
private StringBuilder intermediateResult;

/// <summary>
/// Initialize the internal data structures
/// </summary>
public void Init()
{
this.intermediateResult = new StringBuilder();
}

/// <summary>
/// Accumulate the next value, not if the value is null
/// </summary>
/// <param name="value"></param>
public void Accumulate(SqlString value)
{
if (value.IsNull)
{
return;
}

this.intermediateResult.Append(value.Value).Append(','); /// I want to change to comma to a variable
}

/// <summary>
/// Merge the partially computed aggregate with this aggregate.
/// </summary>
/// <param name="other"></param>
public void Merge(Concatenate other)
{
this.intermediateResult.Append(other.intermediateResult);
}

/// <summary>
/// Called at the end of aggregation, to return the results of the aggregation.
/// </summary>
/// <returns></returns>
public SqlString Terminate()
{
string output = string.Empty;
//delete the trailing comma, if any
if (this.intermediateResult != null
&& this.intermediateResult.Length > 0)
{
output = this.intermediateResult.ToString(0, this.intermediateResult.Length - 1);
}

return new SqlString(output);
}

public void Read(BinaryReader r)
{
intermediateResult = new StringBuilder(r.ReadString());
}

public void Write(BinaryWriter w)
{
w.Write(this.intermediateResult.ToString());
}
}

Hi Rob,

Unfortunately, a current limitation of our UDAs is that they can only take one parameter: the single parameter being aggregated. This precludes a few scenarios, including an additional parameter that is constant for the life of the aggregate (your situation) as well as a second aggregated parameter.

The usual workaround we recommend for folks who want to aggregate over two variables is to wrap them using either XML or a UDT and then unwrap them inside of the aggregate. This could work in your situation as welljust hold one of the variables constantbut is a particularly ugly hack.

Cheers,

-Isaac

|||Hi Isaac,

Since we're considering ugly hacks, I had an idea for another workaround: could I create a table variable, and access it from within my UDA?

E.g., in the following procedure, I create a temp table with params, which my UDA will expect to find in scope when it runs. I have no idea if this would work at all...

CREATE PROCEDURE foo
AS
DECLARE @.settings table (
param1 int,
param2 char
)

SELECT lastName, dbo.myConcatUDA(firstName)
FROM people
GROUP BY lastName

GO

Sunday, February 12, 2012

Clicking on aggregations and displaying transactions?

Greetings SSAS Gurus,

Please please help?

How would I set up my SSAS cube so that when the user clicks on an aggregate, that the transactions that comprise that aggregate, are displayed?

Also, how do I control what is displayed, both in terms of field labels (e.g. labeling the data "Account Balance" instead of "acct_bal_amt", and data values (e.g. seeing "$1,234.56" instead of "1234.56").

Any guidance would be appreciated, even if at a minimum, it consisted of advising me what the topic is called in SSAS so that I can (try:) ) and do the research myself?

In anticipation and appreciation

email: gwithers at jhancock dot com

Greg Withers

In SSAS this concept is called DrillThrough. Depending on whether you use client which support Drillthrough actions (such as Excel 2007) - then it is trivial to define it in the cube. If you are writing the MDX query generation yourself, then take a look at DRILLTHROUGH statement.|||Mosha - Thanks for pointing me in the right direction. I personally prefer being taught to fish, rather than being fed and still not knowing how :)