Dynamic Namespace with XQuery inside SQL Server - xquery-sql

I have a link for my namespace that changes depending on other data. It looks similar to this.
#xml = myXML
#id = myID
#xml.nodes('declare namespace myS="myLink.com/#id";/myS:foo')
Since namespace does not allow variables inside the link because of this error
"Syntax error near 'declare namespace', expected string literal."
Is there anyway to dynamically change the namespace url without hard coding any values.

Because .nodes() expects a string literal and namespaces must be string literals, there is no way to make the namespace dynamic short of constructing the whole statement using dynamic SQL. However, you can select nodes without referring to an explicit namespace declaration. This will select any element named "foo" regardless of namespace:
#xml.nodes('/*[local-name()="foo"]')
If you really need to select an element with a particular dynamic namespace, you can use namespace-uri():
DECLARE #myNS NVARCHAR(MAX) = REPLACE('myLink.com/$id', '$id', #id);
#xml.nodes('/*[local-name()="foo" and namespace-uri()=sql:variable("#myNS")]')
Aside from being clumsy, this may have performance issues -- XPath really likes it if you keep namespaces constant. If possible, change your input so the set of namespaces is well-defined.

Related

Declare variable for shared procedure inside procedure instead Imports statement

I'm using an imports statement to access shared constants and shared procedures just to shorten things a bit.
Imports vList = Helper.Stores.Departments.FruitList
But what I'd really like to do is declare it inside the procedure:
Dim vList as Helper.Stores.Departments.FruitList
Of course I get the warning: Access of shared member, constant member, enum member or nested type through an instance; qualifying expression will not be evaluated. when I try to use it like that.
Is there a way to do something like this inside the procedure without using the imports statement?
As far as I know you can only create an alias of this kind with an import statement as you already done.
The thing that you can do inside a procedure is creating variables using the fully qualified name for the class.
Take a look at the MSDN documentation about Namespaces for more information.

QueryDSL + PathBuilder + cast to string

I am filtering PrimeFaces DataTables using dynamic filters.I have this working using Spring org.springframework.data.jpa.domain.Specification.Now I am wondring how to do the same using QueryDSL.
Using specification I can use javax.persistence.criteria.Root to get a javax.persistence.criteria.Join, use javax.persistence.criteria.Expression.as(Class<String> type) to cast it to String and finally use javax.persistence.criteria.CriteriaBuilder.like(Expression<String> x, String pattern, char escapeChar).
How do I do the same in QueryDSL ? I can get PathBuilder using new PathBuilder<T>(clazz, "entity") (do you really have to use the variable here? I would like my class to be generic...) but then the com.mysema.query.types.path.PathBuilder.get(String property) returns new PathBuilder instead of an Expression.
If I try to use com.mysema.query.types.path.PathBuilder.getString(String property) I get java.lang.IllegalArgumentException: Parameter value [1] did not match expected type [java.lang.Integer].
Seems like the part I am missing is the cast.
I'm quite sure someone was dealing with the same thing already.
Thanks.
Edit: Stack trace for IllegalArgumentException
Trying to search for text "1" inside integer column using com.mysema.query.types.path.PathBuilder.getString(String property) - that's where I need the cast to happen :
Caused by: java.lang.IllegalArgumentException: Parameter value [1] did not match expected type [java.lang.Integer]
at org.hibernate.ejb.AbstractQueryImpl.validateParameterBinding(AbstractQueryImpl.java:375)
at org.hibernate.ejb.AbstractQueryImpl.registerParameterBinding(AbstractQueryImpl.java:348)
at org.hibernate.ejb.QueryImpl.setParameter(QueryImpl.java:375)
at org.hibernate.ejb.QueryImpl.setParameter(QueryImpl.java:442)
at org.hibernate.ejb.QueryImpl.setParameter(QueryImpl.java:72)
at com.mysema.query.jpa.impl.JPAUtil.setConstants(JPAUtil.java:44)
at com.mysema.query.jpa.impl.AbstractJPAQuery.createQuery(AbstractJPAQuery.java:130)
at com.mysema.query.jpa.impl.AbstractJPAQuery.createQuery(AbstractJPAQuery.java:97)
at com.mysema.query.jpa.impl.AbstractJPAQuery.list(AbstractJPAQuery.java:240)
at org.springframework.data.jpa.repository.support.QueryDslJpaRepository.findAll(QueryDslJpaRepository.java:102)
...
To get a valid condition you will need to take the types of the properties into account, e.g.
pathBuilder.getNumber(Integer.class, property).stringValue().like(likePattern)
I was researching a similar topic until I came across this aged question. I hope my answer will be helpful to some.
I think the possible solution lies (exclusively) outside of QueryDSL. You can use common Java reflection to obtain the field type, something like
Class type = clazz.getDeclaredField(criteria.getKey()).getType();
// don't forget to catch exception if field doesn't exist ..
switch(type.getSimpleName()) {
case "String":
StringExpression exp = entityPath.getString(...);
}
That way you can have a reasonably dynamic implementation.

Expression Tree naming conventions

Just a simple question, there aren't a lot of people I know that use Expression Trees so I don't see a lot of resources on how to name them. How would you name an expression variable? Pref. no Hungarian Notations.
For now I just go with:
var newItem = Expression.New(typeof(T));
var itemProperty = Expression.Property(newItem,propertyInfo);
I would call it newExpression and memberExpression perhaps.
To be honest though, I try to limit the number of expression variables I have (i'm content with really long expression declarations that span many lines), obviously parameterexpressions for parameters/variables i declare seperately and I name them as such (ie itemParameter, listVariable)

Escape dot from GString

I would like to learn how to escape dot in GString so groovy (1.8) does not treat it as a part of an variable inside sql.execute. I have the following code:
Map<String, String> dbSettings = [schemaName:"testSchema"];
String myDbPrefix = dbSetting.schemaName + ".";
sql.execute "DELETE FROM ${myDbPrefix}myTable"
And I got this error:
Ignoring groovy.lang.MissingPropertyException: No such property: myTable for class: java.lang.String
Clearly indicating that . was interpreted as part of variable ${myDbPrefix}.
Does escaping the embedded variable help?
  sql.execute "DELETE FROM ${Sql.expand myDbPrefix}myTable"
I got hit by this problem today. GStrings get handled by a special way in GroovySQL. It's mentioned in the javadoc. It does automatic parameter binding.
Each value in the GString will become a parameter (?) which gets set as a JDBC prepared statement parameter.
What a surprise!
I'm going to fix the problem in my application by subclassing the Sql class and overriding the GString handling with plain ".toString()" .
Documented in Groovy wiki:
GString Use Cases - GSQL Another use case for GString is GSQL where
parameters can be passed into SQL statements using this same mechanism
which makes for a neat way to integrate Groovy with other languages
like SQL. GroovySql then converts the expressions to ? and uses a JDBC
PreparedStatement and passes the values in, preserving their types.
If you explicitly want to coerce the GString to a String you can use
the toString() method. Groovy can also automatically coerce GStrings
into Strings for you.

How to retrieve multiple rows from a stored procedure with Linq to SQL?

I've recently started to work with Linq to SQL and wondered how to get multiple rows as a result of executing a stored procedure,here's a simple sp i want to work with:
CREATE PROCEDURE gsp_ftsmultiple
#SearchKey varchar(100)
AS
BEGIN
SET NOCOUNT ON;
SELECT Label, theContent
FROM FtsTest
WHERE FREETEXT( theContent, #SearchKey )
END
Executing this sp from management studio is fine,but the corresponding method in the generated context class returns a int value, and I don't know how to get the actual rows, tried using the OUT parameters, but they can return only one result.
I think all you need to do is make a class that matches your result schema and make sure the function in the dbml has it as a return type.
see here on msdn
Try creating the fulltext predicates as wrapper functions instead of sprocs, like this. Worked for me.
When sqlmetal generates the code for this procedure, it doesn't pass a valid argument for the query to work.
Try to put something like this on the top of you SP:
IF #SearchKey IS NULL OR LEN(#SearchKey) = 0
BEGIN
SELECT N'' AS Label, N'' AS theContent WHERE 1 = 0
END
[...]
It will now deduce that 2 NVARCHAR columns are the usual output and generate code accordingly
PS. Code off my head, untested
Mike
I tested the following code snippet and it worked fine. If you put the generated code here, I can take a look and check where is the problem. Anyway, you can create a partial class as same name as your generated data context class and add the desired method manually as follows.
public partial class FooDataContext: System.Data.Linq.DataContext
{
[System.Data.Linq.Mapping.Function(Name = "GetFoo")]
public System.Data.Linq.ISingleResult<Foo> GetFoo()
{
System.Data.Linq.IExecuteResult res = base.ExecuteMethodCall(this, (System.Reflection.MethodInfo)System.Reflection.MethodInfo.GetCurrentMethod());
return (System.Data.Linq.ISingleResult<Foo>)res.ReturnValue;
}
}
You'd might be better off just running the query in itself, seeing as you're not really doing anything that requires a procedure. Just make sure you escape the search key properly.